
#include "stdafx.h"

#include "globals.h"
#include <math.h>

#ifndef SPI_GETMENUANIMATION
#define SPI_GETMENUANIMATION	0x1002
#endif

#ifndef SPI_GETMENUFADE
#define SPI_GETMENUFADE			0x1012
#endif

#ifndef SPI_GETMENUUNDERLINES
#define SPI_GETKEYBOARDCUES		0x100A
#define SPI_GETMENUUNDERLINES	SPI_GETKEYBOARDCUES
#endif

extern CObList	gAllToolbars;

BOOL CMyMemDC::m_bUseMemoryDC = TRUE;

static const CString strOfficeFontName		= _T("Tahoma");
static const CString strOffice2007FontName	= _T("Segoe UI");
static const CString strDefaultFontName		= _T("MS Sans Serif");
static const CString strVertFontName		= _T("Arial");
static const CString strMarlettFontName		= _T("Marlett");


/************************************************************************/
/*                                                                      */
/************************************************************************/

const double PI = 3.1415926;

#define CLR_TO_RGBA(c) c | 0xFF000000
#define RGB_TO_RGBA(r, g, b) CLR_TO_RGBA(RGB(r, g, b))
#define _RGBA(r, g, b, a) RGB(r, g, b) | (a << 24)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

HBITMAP CMyDrawManager::CreateBitmap_32 (const CSize& size, void** pBits)
{
	ASSERT (0 < size.cx);
	ASSERT (0 != size.cy);

	if (pBits != NULL)
	{
		*pBits = NULL;
	}

	if (size.cx <= 0 || size.cy == 0)
	{
		return NULL;
	}

	BITMAPINFO bi = {0};

	// Fill in the BITMAPINFOHEADER
	bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	bi.bmiHeader.biWidth       = size.cx;
	bi.bmiHeader.biHeight      = size.cy;
	bi.bmiHeader.biSizeImage   = size.cx * size.cy;
	bi.bmiHeader.biPlanes      = 1;
	bi.bmiHeader.biBitCount    = 32;
	bi.bmiHeader.biCompression = BI_RGB;

	LPVOID pData = NULL;
	HBITMAP hbmp = ::CreateDIBSection (NULL, &bi, DIB_RGB_COLORS, &pData, NULL, 0);

	if (pData != NULL && hbmp != NULL && pBits != NULL)
	{
		*pBits = pData;
	}

	return hbmp;
}

HBITMAP CMyDrawManager::CreateBitmap_32 (HBITMAP bitmap, COLORREF clrTransparent/* = -1*/)
{
	if (bitmap == NULL)
	{
		ASSERT (FALSE);
		return NULL;
	}

	BITMAP bmp;
	if (::GetObject (bitmap, sizeof (BITMAP), &bmp) == 0)
	{
		ASSERT (FALSE);
		return NULL;
	}

	if (bmp.bmBits == NULL)
	{
		ASSERT (FALSE);
		return NULL;
	}

	LPVOID lpBits = NULL;
	HBITMAP hbmp = CreateBitmap_32 (CSize (bmp.bmWidth, bmp.bmHeight), &lpBits);

	if (hbmp != NULL)
	{
		DWORD nSizeImage = bmp.bmWidth * bmp.bmHeight;

		if (bmp.bmBitsPixel == 32)
		{
			memcpy (lpBits, bmp.bmBits, nSizeImage * 4);
		}
		else
		{
			CDC dcSrc;
			dcSrc.CreateCompatibleDC (NULL);
			HBITMAP hbmpSrc = (HBITMAP) dcSrc.SelectObject (bitmap);

			if (hbmpSrc != NULL)
			{
				CDC dcDst;
				dcDst.CreateCompatibleDC (NULL);
				HBITMAP hbmpDst = (HBITMAP) dcDst.SelectObject (hbmp);

				dcDst.BitBlt (0, 0, bmp.bmWidth, bmp.bmHeight, &dcSrc, 0, 0, SRCCOPY);

				dcDst.SelectObject (hbmpDst);
				dcSrc.SelectObject (hbmpSrc);

				COLORREF* pBits = (COLORREF*) lpBits;
				if (clrTransparent == -1)
				{
					for (DWORD i = 0; i < nSizeImage; i++)
					{
						*pBits |= 0xFF000000;
						pBits++;
					}
				}
				else
				{
					COLORREF clrTrans = RGB (GetBValue (clrTransparent),
											 GetGValue (clrTransparent),
											 GetRValue (clrTransparent));

					for (DWORD i = 0; i < nSizeImage; i++)
					{
						if (*pBits != clrTrans)
						{
							*pBits |= 0xFF000000;
						}
						else
						{
							*pBits = (COLORREF) 0;
						}

						pBits++;
					}
				}
			}
		}
	}

	return hbmp;
}

CMyDrawManager::CMyDrawManager(CDC& m_dc) :
	m_dc (m_dc)
{
}
//*************************************************************************************
CMyDrawManager::~CMyDrawManager()
{
}
//*************************************************************************************
BOOL CMyDrawManager::HighlightRect (CRect rect, int nPercentage, COLORREF clrTransparent,
									  int nTolerance, COLORREF clrBlend)
{
	if (nPercentage == 100)
	{
		// Nothing to do
		return TRUE;
	}

	if (rect.Height () <= 0 || rect.Width () <= 0)
	{
		return TRUE;
	}

	if (globalData.m_nBitsPerPixel <= 8)
	{
		CMFCToolBarImages::FillDitheredRect(&m_dc, rect);
		return TRUE;
	}

	if (clrBlend != (COLORREF)-1 && nPercentage > 100)
	{
		return FALSE;
	}

	int cx = rect.Width ();
	int cy = rect.Height ();

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, cx, cy))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx, cy), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return FALSE;
	}

	dcMem.SelectObject (hmbpDib);
	dcMem.BitBlt (0, 0, cx, cy, &m_dc, rect.left, rect.top, SRCCOPY);

	if (clrTransparent != -1)
	{
		clrTransparent = RGB (GetBValue(clrTransparent), GetGValue(clrTransparent), GetRValue(clrTransparent));
	}

	for (int pixel = 0; pixel < cx * cy; pixel++, *pBits++)
	{
		COLORREF color = (COLORREF) *pBits;

		BOOL bIgnore = FALSE;

		if (nTolerance > 0)
		{
			bIgnore = (	abs (GetRValue (color) - GetRValue (clrTransparent)) < nTolerance &&
						abs (GetGValue (color) - GetGValue (clrTransparent)) < nTolerance &&
						abs (GetBValue (color) - GetBValue (clrTransparent)) < nTolerance);
		}
		else
		{
			bIgnore = color == clrTransparent;
		}

		if (!bIgnore)
		{
			if (nPercentage == -1)
			{
				*pBits = RGB_TO_RGBA (
					min (255, (2 * GetRValue (color) + GetBValue (globalData.clrBtnHilite)) / 3),
					min (255, (2 * GetGValue (color) + GetGValue (globalData.clrBtnHilite)) / 3),
					min (255, (2 * GetBValue (color) + GetRValue (globalData.clrBtnHilite)) / 3));
			}
			else
			{
				if (clrBlend == (COLORREF)-1)
				{
					*pBits = CLR_TO_RGBA (PixelAlpha (color, 
						.01 * nPercentage, .01 * nPercentage, .01 * nPercentage));
				}
				else
				{
					long R = GetRValue (color);
					long G = GetGValue (color);
					long B = GetBValue (color);

					*pBits = RGB_TO_RGBA (
						min (255, R + ::MulDiv (GetBValue (clrBlend) - R, nPercentage, 100)),
						min (255, G + ::MulDiv (GetGValue (clrBlend) - G, nPercentage, 100)),
						min (255, B + ::MulDiv (GetRValue (clrBlend) - B, nPercentage, 100))
						);
				}
			}
		}
	}

	//-------------------------------------------
	// Copy highligted bitmap back to the screen:
	//-------------------------------------------
	m_dc.BitBlt (rect.left, rect.top, cx, cy, &dcMem, 0, 0, SRCCOPY);

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);

	return TRUE;
}
//*********************************************************************************
void CMyDrawManager::MirrorRect (CRect rect, BOOL bHorz/* = TRUE*/)
{
	if (rect.Height () <= 0 || rect.Width () <= 0)
	{
		return;
	}

	CRect rectClip;
	m_dc.GetClipBox (rectClip);

	CRect rectUnion;
	rectUnion.UnionRect (rectClip, rect);

	if (rectUnion != rectClip)
	{
		return;
	}

	int cx = rect.Width ();
	int cy = rect.Height ();

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, cx, cy))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx, cy), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	dcMem.SelectObject (hmbpDib);
	dcMem.BitBlt (0, 0, cx, cy, &m_dc, rect.left, rect.top, SRCCOPY);

	if (bHorz)
	{
		for (int y = 0; y <= cy; y++)
		{
			for (int x = 0; x <= cx / 2; x++)
			{
				int xRight = cx - x - 1;
				int y1 = cy - y;

				if (cx * y1 + x >= cx * cy ||  
					cx * y1 + xRight >= cx * cy)
				{
					continue;
				}

				COLORREF* pColorLeft = (COLORREF*) (pBits + cx * y1 + x);
				COLORREF colorSaved = *pColorLeft;

				COLORREF* pColorRight = (COLORREF*) (pBits + cx * y1 + xRight);

				*pColorLeft = *pColorRight;
				*pColorRight = colorSaved;
			}
		}
	}
	else
	{
		for (int y = 0; y <= cy / 2; y++)
		{
			for (int x = 0; x < cx; x++)
			{
				int yBottom = cy - y - 1;

				COLORREF* pColorTop = (COLORREF*) (pBits + cx * y + x);
				COLORREF colorSaved = *pColorTop;

				COLORREF* pColorBottom = (COLORREF*) (pBits + cx * yBottom + x);

				*pColorTop = *pColorBottom;
				*pColorBottom = colorSaved;
			}
		}
	}

	m_dc.BitBlt (rect.left, rect.top, cx, cy, &dcMem, 0, 0, SRCCOPY);

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);
}
//*************************************************************************************
BOOL CMyDrawManager::GrayRect (CRect rect, int nPercentage, COLORREF clrTransparent,
								 COLORREF clrDisabled)
{
	if (rect.Height () <= 0 || rect.Width () <= 0)
	{
		return TRUE;
	}

	if (globalData.m_nBitsPerPixel <= 8)
	{
		CMFCToolBarImages::FillDitheredRect (&m_dc, rect);
		return TRUE;
	}

	int cx = rect.Width ();
	int cy = rect.Height ();

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, cx, cy))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx, cy), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return FALSE;
	}

	dcMem.SelectObject (hmbpDib);
	dcMem.BitBlt (0, 0, cx, cy, &m_dc, rect.left, rect.top, SRCCOPY);

	if (clrTransparent != (COLORREF)-1)
	{
		clrTransparent = RGB (GetBValue(clrTransparent), GetGValue(clrTransparent), GetRValue(clrTransparent));
	}

	if (clrDisabled == (COLORREF)-1)
	{
		clrDisabled = globalData.clrBtnHilite;
	}

	for (int pixel = 0; pixel < cx * cy; pixel++, *pBits++)
	{
		COLORREF color = (COLORREF) *pBits;
		if (color != clrTransparent)
		{
			double H,S,L;
			RGBtoHSL(color, &H, &S, &L);
			color = HLStoRGB_ONE(H,L,0);
			
			if (nPercentage == -1)
			{
				*pBits = RGB_TO_RGBA (
					min (255, GetRValue (color) + ((GetBValue (clrDisabled) -
					GetRValue (color)) / 2)),
					min (255, GetGValue (color) + ((GetGValue (clrDisabled) -
					GetGValue (color)) / 2)),
					min (255, GetBValue(color) + ((GetRValue (clrDisabled) -
					GetBValue (color)) / 2)));
			}
			else
			{
				*pBits = CLR_TO_RGBA (PixelAlpha (color, .01 * nPercentage, .01 * nPercentage, .01 * nPercentage));
			}
		}
	}
	
	//-------------------------------------------
	// Copy highligted bitmap back to the screen:
	//-------------------------------------------
	m_dc.BitBlt (rect.left, rect.top, cx, cy, &dcMem, 0, 0, SRCCOPY);

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);

	return TRUE;
} 
//*************************************************************************************
void CMyDrawManager::_FillGradient (CRect rect, 
									COLORREF colorStart, COLORREF colorFinish, 
									BOOL bHorz/* = TRUE*/,
									int nStartFlatPercentage/* = 0*/,
									int nEndFlatPercentage/* = 0*/)
{
	if (colorStart == colorFinish)
	{
		CBrush br (colorStart);
		m_dc.FillRect (rect, &br);
		return;
	}

	if (nStartFlatPercentage > 0)
	{
		ASSERT (nStartFlatPercentage <= 100);

		if (bHorz)
		{
			CRect rectTop = rect;
			rectTop.bottom = rectTop.top + 
				rectTop.Height () * nStartFlatPercentage / 100;
			rect.top = rectTop.bottom;

			CBrush br (colorFinish);
			m_dc.FillRect (rectTop, &br);
		}
		else
		{
			CRect rectLeft = rect;
			rectLeft.right = rectLeft.left + 
				rectLeft.Width () * nStartFlatPercentage / 100;
			rect.left = rectLeft.right;

			CBrush br (colorStart);
			m_dc.FillRect (rectLeft, &br);
		}
	}

	if (nEndFlatPercentage > 0)
	{
		ASSERT (nEndFlatPercentage <= 100);

		if (bHorz)
		{
			CRect rectBottom = rect;
			rectBottom.top = rectBottom.bottom - 
				rectBottom.Height () * nEndFlatPercentage / 100;
			rect.bottom = rectBottom.top;

			CBrush br (colorStart);
			m_dc.FillRect (rectBottom, &br);
		}
		else
		{
			CRect rectRight = rect;
			rectRight.left = rectRight.right - 
				rectRight.Width () * nEndFlatPercentage / 100;
			rect.right = rectRight.left;

			CBrush br (colorFinish);
			m_dc.FillRect (rectRight, &br);
		}
	}

	if (nEndFlatPercentage + nStartFlatPercentage > 100)
	{
		ASSERT (FALSE);
		return;
	}

    // this will make 2^6 = 64 fountain steps
    int nShift = 6;
    int nSteps = 1 << nShift;

    for (int i = 0; i < nSteps; i++)
    {
        // do a little alpha blending
        BYTE bR = (BYTE) ((GetRValue(colorStart) * (nSteps - i) +
                   GetRValue(colorFinish) * i) >> nShift);
        BYTE bG = (BYTE) ((GetGValue(colorStart) * (nSteps - i) +
                   GetGValue(colorFinish) * i) >> nShift);
        BYTE bB = (BYTE) ((GetBValue(colorStart) * (nSteps - i) +
                   GetBValue(colorFinish) * i) >> nShift);

		CBrush br (RGB(bR, bG, bB));

        // then paint with the resulting color
        CRect r2 = rect;
        if (bHorz)
        {
            r2.bottom = rect.bottom - 
                ((i * rect.Height()) >> nShift);
            r2.top = rect.bottom - 
                (((i + 1) * rect.Height()) >> nShift);
            if (r2.Height() > 0)
                m_dc.FillRect(r2, &br);
        }
        else
        {
            r2.left = rect.left + 
                ((i * rect.Width()) >> nShift);
            r2.right = rect.left + 
                (((i + 1) * rect.Width()) >> nShift);
            if (r2.Width() > 0)
                m_dc.FillRect(r2, &br);
        }
    }
}
void CMyDrawManager::FillGradient (CRect rect, 
									COLORREF colorStart, COLORREF colorFinish, 
									BOOL bHorz/* = TRUE*/,
									int nStartFlatPercentage/* = 0*/,
									int nEndFlatPercentage/* = 0*/)
{
	if (!CMFCToolBarImages::m_bIsDrawOnGlass)
	{
		_FillGradient (rect, colorStart, colorFinish, bHorz,
						 nStartFlatPercentage, nEndFlatPercentage);
	}
	else
	{
		CRect rt (rect);
		rt.NormalizeRect ();

		CSize size (rt.Size ());
		if (size.cx == 0 || size.cy == 0)
		{
			return;
		}

		//--------------------------------------------
		// Copy screen content into the memory bitmap:
		//--------------------------------------------
		CDC dcMem;
		if (!dcMem.CreateCompatibleDC (&m_dc))
		{
			ASSERT (FALSE);
			return;
		}

		//--------------------------------------------
		// Gets the whole menu and changes the shadow.
		//--------------------------------------------
		CBitmap	bmpMem;
		if (!bmpMem.CreateCompatibleBitmap (&m_dc, size.cx, size.cy))
		{
			ASSERT (FALSE);
			return;
		}

		CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
		ASSERT (pOldBmp != NULL);

		COLORREF* pBits;
		HBITMAP hmbpDib = CreateBitmap_32 (size, (LPVOID*)&pBits);

		if (hmbpDib == NULL || pBits == NULL)
		{
			ASSERT (FALSE);
			return;
		}

		dcMem.SelectObject (hmbpDib);

		CMyDrawManager dm (dcMem);
		dm._FillGradient (CRect (CPoint (0, 0), size), colorStart, colorFinish, bHorz,
						 nStartFlatPercentage, nEndFlatPercentage);

		int sizeImage = size.cx * size.cy;
		for (int i = 0; i < sizeImage; i++)
		{
			*pBits |= 0xFF000000;
			pBits++;
		}

		//--------------------------------
		// Copy bitmap back to the screen:
		//--------------------------------

		m_dc.BitBlt (rt.left, rt.top, size.cx, size.cy, &dcMem, 0, 0, SRCCOPY);

		dcMem.SelectObject (pOldBmp);
		DeleteObject (hmbpDib);
	}
}
//************************************************************************************
void CMyDrawManager::FillGradient2 (CRect rect, COLORREF colorStart, COLORREF colorFinish, 
					int nAngle)
{
	if (rect.Width () <= 0 || rect.Height () <= 0)
	{
		return;
	}

	if (colorStart == colorFinish)
	{
		CBrush br (colorStart);
		m_dc.FillRect (rect, &br);
		return;
	}

	//----------------------
	// Process simple cases:
	//----------------------
	switch (nAngle)
	{
	case 0:
	case 360:
		FillGradient (rect, colorStart, colorFinish, FALSE);
		return;

	case 90:
		FillGradient (rect, colorStart, colorFinish, TRUE);
		return;

	case 180:
		FillGradient (rect, colorFinish, colorStart, FALSE);
		return;

	case 270:
		FillGradient (rect, colorFinish, colorStart, TRUE);
		return;
	}

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, rect.Width (), rect.Height ()))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject (&bmpMem);
	ASSERT (pOldBmp != NULL);

	CPen* pOldPen = (CPen*) dcMem.SelectStockObject (NULL_PEN);

    int nShift = 6;
    int nSteps = 1 << nShift;

	const double fAngle = PI * (nAngle + 180) / 180;
	const int nOffset = (int) (cos(fAngle) * rect.Height ());
	const int nTotalWidth = rect.Width () + abs (nOffset);

	const int xStart = nOffset > 0 ? - nOffset : 0;

    for (int i = 0; i < nSteps; i++)
    {
        // do a little alpha blending
        BYTE bR = (BYTE) ((GetRValue(colorStart) * (nSteps - i) +
                   GetRValue(colorFinish) * i) >> nShift);
        BYTE bG = (BYTE) ((GetGValue(colorStart) * (nSteps - i) +
                   GetGValue(colorFinish) * i) >> nShift);
        BYTE bB = (BYTE) ((GetBValue(colorStart) * (nSteps - i) +
                   GetBValue(colorFinish) * i) >> nShift);

		CBrush br (RGB (bR, bG, bB));

        int x11 = xStart + ((i * nTotalWidth) >> nShift);
        int x12 = xStart + (((i + 1) * nTotalWidth) >> nShift);

		if (x11 == x12)
		{
			continue;
		}

		int x21 = x11 + nOffset;
		int x22 = x21 + (x12 - x11);

		POINT points [4];
		points [0].x = x11;
		points [0].y = 0;
		points [1].x = x12;
		points [1].y = 0;
		points [2].x = x22;
		points [2].y = rect.Height ();
		points [3].x = x21;
		points [3].y = rect.Height ();

		CBrush* pOldBrush = dcMem.SelectObject (&br);
		dcMem.Polygon (points, 4);
		dcMem.SelectObject (pOldBrush);
	}

	dcMem.SelectObject (pOldPen);

	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------
	m_dc.BitBlt (rect.left, rect.top, rect.Width (), rect.Height (), &dcMem, 0, 0, SRCCOPY);
	dcMem.SelectObject (pOldBmp);
}
//************************************************************************************
void CMyDrawManager::Fill4ColorsGradient (CRect rect, 
	COLORREF colorStart1, COLORREF colorFinish1, 
	COLORREF colorStart2, COLORREF colorFinish2,
	BOOL bHorz/* = TRUE*/,
	int nPercentage)	/* = 50, 0 - 100 */
{
	ASSERT (nPercentage >= 0);
	ASSERT (nPercentage <= 100);

	CRect rectFirst = rect;
	CRect rectSecond = rect;

	if (!bHorz)
	{
		rectFirst.right = rectFirst.left + rectFirst.Width () * nPercentage / 100;
		rectSecond.left = rectFirst.right;
	}
	else
	{
		rectFirst.bottom = rectFirst.top + rectFirst.Height () * nPercentage / 100;
		rectSecond.top = rectFirst.bottom;
	}

	FillGradient (rectFirst, colorStart1, colorFinish1, bHorz);
	FillGradient (rectSecond, colorStart2, colorFinish2, bHorz);
}
//************************************************************************************
BOOL CMyDrawManager::DrawGradientRing (CRect rect,
					   COLORREF colorStart, COLORREF colorFinish,
					   COLORREF colorBorder,
					   int nAngle /* 0 - 360 */,
					   int nWidth,
					   COLORREF clrFace /* = -1 */)
{
	int cx = rect.Width ();
	int cy = rect.Height ();

	if (cx <= 4 || cy <= 4)
	{
		//--------------------
		// Rectangle too small
		//--------------------
		return FALSE;
	}

	int xOrig = rect.left;
	int yOrig = rect.top;

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, cx, cy))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx, cy), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return FALSE;
	}

	dcMem.SelectObject (hmbpDib);
	dcMem.BitBlt (0, 0, cx, cy, &m_dc, rect.left, rect.top, SRCCOPY);

	rect.OffsetRect (-xOrig, -yOrig);

	const int xCenter = (rect.left + rect.right) / 2;
	const int yCenter = (rect.top + rect.bottom) / 2;

	const int nSteps = 360;
	const double fDelta = 2. * PI / nSteps;
	const double fStart = PI * nAngle / 180;
	const double fFinish = fStart + 2. * PI;

	double rDelta = (double) (.5 + GetRValue (colorFinish) - GetRValue (colorStart)) / nSteps * 2;
	double gDelta = (double) (.5 + GetGValue (colorFinish) - GetGValue (colorStart)) / nSteps * 2;
	double bDelta = (double) (.5 + GetBValue (colorFinish) - GetBValue (colorStart)) / nSteps * 2;

	for (int nLevel = 0; nLevel < nWidth; nLevel++)
	{
		int i = 0;
		const int nRadius = min (rect.Width (), rect.Height ()) / 2;
		const int nRectDelta = rect.Width () - rect.Height ();

		if (clrFace != (COLORREF) -1 && nLevel == 0)
		{
			//---------------
			// Fill interior:
			//---------------
			CBrush brFill (clrFace);
			CBrush* pOldBrush = dcMem.SelectObject (&brFill);
			CPen* pOldPen = (CPen*) dcMem.SelectStockObject (NULL_PEN);

			if (nRectDelta == 0)	// Circle
			{
				dcMem.Ellipse (rect);
			}
			else if (nRectDelta > 0)	// Horizontal
			{
				dcMem.Ellipse (rect.left, rect.top, rect.left + rect.Height (), rect.bottom);
				dcMem.Ellipse (rect.right - rect.Height (), rect.top, rect.right, rect.bottom);
				dcMem.Rectangle (rect.left + rect.Height () / 2, rect.top, rect.right - rect.Height () / 2, rect.bottom);
			}
			else	// Vertical
			{
				dcMem.Ellipse (rect.left, rect.top, rect.right, rect.top + rect.Width ());
				dcMem.Ellipse (rect.left, rect.bottom - rect.Width (), rect.right, rect.bottom);
				dcMem.Rectangle (rect.left, rect.top + rect.Width () / 2, rect.right, rect.bottom - rect.Width () / 2);
			}

			dcMem.SelectObject (pOldBrush);
			dcMem.SelectObject (pOldPen);
		}

		int xPrev = -1;
		int yPrev = -1;

		for (double fAngle = fStart; fAngle < fFinish + fDelta; fAngle += fDelta, i ++)
		{
			const int nStep = fAngle <= (fFinish + fStart) / 2 ? i : nSteps - i;

			const BYTE bR = (BYTE) max (0, min (255, (.5 + rDelta * nStep + GetRValue (colorStart))));
			const BYTE bG = (BYTE) max (0, min (255, (.5 + gDelta * nStep + GetGValue (colorStart))));
			const BYTE bB = (BYTE) max (0, min (255, (.5 + bDelta * nStep + GetBValue (colorStart))));

			COLORREF color = nLevel == 0 && colorBorder != -1 ? 
				colorBorder : RGB (bR, bG, bB);

			double dx = /*(fAngle >= 0 && fAngle <= PI / 2) || (fAngle >= 3 * PI / 2) ?
				.5 : -.5*/0;
			double dy = /*(fAngle <= PI) ? .5 : -.5*/0;

			int x = xCenter + (int) (dx + cos (fAngle) * nRadius);
			int y = yCenter + (int) (dy + sin (fAngle) * nRadius);

			if (nRectDelta > 0)
			{
				if (x > xCenter)
				{
					x += (int) (.5 * nRectDelta);
				}
				else
				{
					x -= (int) (.5 * nRectDelta);
				}

				if (xPrev != -1 && (xPrev > xCenter) != (x > xCenter))
				{
					for (int x1 = min (x, xPrev); x1 < max (x, xPrev); x1++)
					{
						SetPixel (pBits, cx, cy, x1, y, color);
					}
				}
			}
			else if (nRectDelta < 0)
			{
				if (y > yCenter)
				{
					y -= (int) (.5 * nRectDelta);
				}
				else
				{
					y += (int) (.5 * nRectDelta);
				}

				if (yPrev != -1 && (yPrev > yCenter) != (y > yCenter))
				{
					for (int y1 = min (y, yPrev); y1 < max (y, yPrev); y1++)
					{
						SetPixel (pBits, cx, cy, x, y1, color);
					}
				}
			}

			SetPixel (pBits, cx, cy, x, y, color);

			xPrev = x;
			yPrev = y;
		}

		rect.DeflateRect (1, 1);
	}


	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------
	m_dc.BitBlt (xOrig, yOrig, cx, cy, &dcMem, 0, 0, SRCCOPY);

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);

	return TRUE;
}
//*************************************************************************************
BOOL CMyDrawManager::DrawShadow (CRect rect, int nDepth,
								  int iMinBrightness, int iMaxBrightness,
								  CBitmap* pBmpSaveBottom,
								  CBitmap* pBmpSaveRight,
								  COLORREF clrBase,
								  BOOL bRightShadow/* = TRUE*/)
{
	ASSERT (nDepth >= 0);

	if (nDepth == 0 || rect.IsRectEmpty ())
	{
		return TRUE;
	}

	int cx = rect.Width ();
	int cy = rect.Height ();

	const BOOL bIsLeft = !bRightShadow;

	if (pBmpSaveRight != NULL && pBmpSaveRight->GetSafeHandle () != NULL &&
		pBmpSaveBottom != NULL && pBmpSaveBottom->GetSafeHandle () != NULL)
	{
		//---------------------------------------------------
		// Shadows are already implemented, put them directly
		// to the DC:
		//---------------------------------------------------
		m_dc.DrawState (CPoint (
						bIsLeft ? rect.left - nDepth : rect.right, 
						rect.top),
					CSize (nDepth, cy + nDepth),
					pBmpSaveRight, DSS_NORMAL);

		m_dc.DrawState (CPoint (
					bIsLeft ? rect.left - nDepth : rect.left, 
					rect.bottom),
					CSize (cx + nDepth, nDepth),
					pBmpSaveBottom, DSS_NORMAL);
		return TRUE;
	}

	ASSERT (pBmpSaveRight == NULL || pBmpSaveRight->GetSafeHandle () == NULL);
	ASSERT (pBmpSaveBottom == NULL || pBmpSaveBottom->GetSafeHandle () == NULL);

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, cx + nDepth, cy + nDepth))
	{
		ASSERT (FALSE);
		return FALSE;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx + nDepth, cy + nDepth), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return FALSE;
	}

	dcMem.SelectObject (hmbpDib);
	dcMem.BitBlt (0, 0, cx + nDepth, cy + nDepth, &m_dc, 
		bIsLeft ? rect.left - nDepth : rect.left, 
		rect.top, SRCCOPY);

	BOOL bOldAlgorithm = TRUE;

	if (globalData.bIsOSAlphaBlendingSupport)
	{
		CMFCShadowRenderer shadow;
		if (shadow.Create(nDepth, clrBase, 100 - iMinBrightness, 100 - iMaxBrightness))
		{
			if (CMFCToolBarImages::IsRTL ())
			{
				shadow.Mirror();
			}
			shadow.DrawFrame (&dcMem, CRect (nDepth, nDepth, cx + nDepth, cy + nDepth));
			bOldAlgorithm = FALSE;
		}
	}

	if (bOldAlgorithm)
	{
		//----------------------------------------------------------------------------
		// Process shadowing:
		// For having a very nice shadow effect, its actually hard work. Currently,
		// I'm using a more or less "hardcoded" way to set the shadows (by using a
		// hardcoded algorythm):
		//
		// This algorythm works as follows:
		// 
		// It always draws a few lines, from left to bottom, from bottom to right,
		// from right to up, and from up to left). It does this for the specified
		// shadow width and the color settings.
		//-----------------------------------------------------------------------------

		// For speeding up things, iShadowOffset is the
		// value which is needed to multiply for each shadow step
		int iShadowOffset = (iMaxBrightness - iMinBrightness) / nDepth;

		// Loop for drawing the shadow
		// Actually, this was simpler to implement than I thought
		for (int c = 0; c < nDepth; c++)
		{
			// Draw the shadow from left to bottom
			for (int y = cy; y < cy + (nDepth - c); y++)
			{
				SetAlphaPixel (pBits, rect, c + nDepth, y, 
					iMaxBrightness - ((nDepth  - c) * (iShadowOffset)), nDepth, clrBase, bIsLeft);
			}

			// Draw the shadow from left to right
			for (int x = nDepth + (nDepth - c); x < cx + c; x++)
			{
				SetAlphaPixel(pBits, rect,x, cy + c,
					iMaxBrightness - ((c) * (iShadowOffset)),nDepth, clrBase, bIsLeft);
			}

			// Draw the shadow from top to bottom
			for (int y1 = nDepth + (nDepth - c); y1 < cy + c + 1; y1++)
			{
				SetAlphaPixel(pBits, rect, cx+c, y1, 
					iMaxBrightness - ((c) * (iShadowOffset)),
					nDepth, clrBase, bIsLeft);
			}
			
			// Draw the shadow from top to left
			for (int x1 = cx; x1 < cx + (nDepth - c); x1++)
			{
				SetAlphaPixel (pBits, rect, x1, c + nDepth,
					iMaxBrightness - ((nDepth - c) * (iShadowOffset)),
					nDepth, clrBase, bIsLeft);
			}
		}
	}

	//-----------------------------------------
	// Copy shadowed bitmap back to the screen:
	//-----------------------------------------
	m_dc.BitBlt (bIsLeft ? rect.left - nDepth : rect.left, 
		rect.top, 
		cx + nDepth, cy + nDepth, &dcMem, 0, 0, SRCCOPY);

	//------------------------------------
	// Save shadows in the memory bitmaps:
	//------------------------------------
	if (pBmpSaveRight != NULL)
	{
		pBmpSaveRight->CreateCompatibleBitmap (&m_dc, nDepth + 1, cy + nDepth);
		
		dcMem.SelectObject (pBmpSaveRight);
		dcMem.BitBlt (0, 0, nDepth, cy + nDepth,
			&m_dc, bIsLeft ? 0 : rect.right, rect.top, SRCCOPY);
	}

	if (pBmpSaveBottom != NULL)
	{
		pBmpSaveBottom->CreateCompatibleBitmap (&m_dc, cx + nDepth, nDepth + 1);

		dcMem.SelectObject (pBmpSaveBottom);
		dcMem.BitBlt (0, 0, cx + nDepth, nDepth, &m_dc,
						bIsLeft ? rect.left - nDepth : rect.left, 
						rect.bottom, SRCCOPY);
	}

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);

	return TRUE;
}

inline int sqr(int value)
{
	return value * value;
};

inline double sqr(double value)
{
	return value * value;
};

inline int sign(int value)
{
	if (value == 0)
	{
		return 0;
	}
	else
	{
		if (value > 0)
		{
			return 1;
		}
	}

	return -1;
}

inline double sign(double value)
{
	if (value == 0.0)
	{
		return 0.0;
	}
	else
	{
		if (value > 0.0)
		{
			return 1.0;
		}
	}

	return -1.0;
}

inline double frac(double value)
{
	return value - floor(value);
}

void CMyDrawManager::DrawLine (int x1, int y1, int x2, int y2, COLORREF clrLine)
{
	if (clrLine == -1)
	{
		return;
	}

    int x  = x1;
    int y  = y1;
	int dx = abs(x2 - x1);
    int dy = abs(y2 - y1);
    int sx = sign(x2 - x1);
    int sy = sign(y2 - y1);

    if(dx == 0 && dy == 0)
    {
        return;
    }

	CRect rect (x1, y1, x2, y2);
	rect.NormalizeRect ();
	rect.InflateRect (0, 0, 1, 1);

	CSize size (rect.Size ());
	if (size.cx == 0 || size.cy == 0)
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, size.cx, size.cy))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (size, (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	dcMem.SelectObject (hmbpDib);


	ALPHABLEND m_pfAlphaBlend = NULL;
	HMODULE hT = LoadLibrary (_T("msimg32.dll"));
	if(NULL!=hT)
	{
		m_pfAlphaBlend = (ALPHABLEND)::GetProcAddress (hT, "AlphaBlend");
	}
	if (m_pfAlphaBlend == NULL || globalData.bIsWindows9x)
	{
		dcMem.BitBlt (0, 0, size.cx, size.cy, &m_dc, rect.left, rect.top, SRCCOPY);
	}

	bool exch = false;

    if(dy > dx)
    {
        long z = dx;
        dx = dy;
        dy = z;
        exch = true;
    }

    long e = 2 * dy - dx;
    long i = 1;

	clrLine = RGB (GetBValue (clrLine), GetGValue (clrLine), GetRValue (clrLine)) | 0xFF000000;

    do
    {
		*(pBits + (size.cy - (y - rect.top) - 1) * size.cx + (x - rect.left)) = clrLine;

        while (e >= 0)
        {
            if (exch)
            {
                x += sx;
            }
            else
            {
                y += sy;
            }

            e -= 2 * dx;
        }

        if (exch)
        {
            y += sy;
        }
        else
        {
            x += sx;
        }

        e += 2 * dy;

        i++;
    }
    while (i <= dx);

	*(pBits + (size.cy - (y - rect.top) - 1) * size.cx + (x - rect.left)) = clrLine;

	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------

	DrawAlpha (&m_dc, rect, &dcMem, CRect (CPoint (0, 0), size));

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);
}

void CMyDrawManager::DrawLineA (double x1, double y1, double x2, double y2, COLORREF clrLine)
{
	if (clrLine == -1)
	{
		return;
	}

	double xd = x2 - x1;
    double yd = y2 - y1;

    if(xd == 0 && yd == 0)
    {
        return;
    }

	bool exch = false;

    if (fabs(xd) <= fabs(yd))
    {
        exch = true;

        double tmpreal = x1;
        x1 = y1;
        y1 = tmpreal;

        tmpreal = x2;
        x2 = y2;
        y2 = tmpreal;

        tmpreal = xd;
        xd = yd;
        yd = tmpreal;
    }

    if (x1 > x2)
    {
        double tmpreal = x1;
        x1 = x2;
        x2 = tmpreal;

        tmpreal = y1;
        y1 = y2;
        y2 = tmpreal;

        xd = x2 - x1;
        yd = y2 - y1;
    }

	double f1 = 0.0;
	double f2 = 0.0;
	double f3 = 0.0;
	double f4 = 0.0;

	double grad = yd / xd;
	double yf;

	int ix1, ix2, iy1, iy2;

	{
		double xend = floor (x1 + 0.5);
		double yend = y1 + grad * (xend - x1);
		double xgap = 1.0 - frac (x1 + 0.5);
		ix1         = (int)floor (x1 + 0.5);
		iy1         = (int)floor (yend);

		f1 = (1.0 - frac (yend)) * xgap;
		f2 = frac (yend) * xgap;

		yf          = yend + grad;
		xend        = floor (x2 + 0.5);
		yend        = y2 + grad * (xend - x2);
		xgap        = 1.0 - frac (x2 - 0.5);
		ix2         = (int)floor (x2 + 0.5);
		iy2         = (int)floor (yend);

		f3 = (1.0 - frac (yend)) * xgap;
		f4 = frac (yend) * xgap;
	}

	CRect rect (ix1, iy1, ix2, iy2);

	if (exch)
	{
		rect = CRect (iy1, ix1, iy2, ix2);
	}

	rect.NormalizeRect ();
	rect.InflateRect (0, 0, 1, 1);

	if (exch)
	{
		rect.right++;
	}
	else
	{
		rect.bottom++;
	}

	CSize size (rect.Size ());
	if (size.cx == 0 || size.cy == 0)
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, size.cx, size.cy))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (size, (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	dcMem.SelectObject (hmbpDib);

	ALPHABLEND m_pfAlphaBlend = NULL;
	HMODULE hT = LoadLibrary (_T("msimg32.dll"));
	if(NULL!=hT)
	{
		m_pfAlphaBlend = (ALPHABLEND)::GetProcAddress (hT, "AlphaBlend");
	}
	if (m_pfAlphaBlend == NULL || globalData.bIsWindows9x)
	{
		dcMem.BitBlt (0, 0, size.cx, size.cy, &m_dc, rect.left, rect.top, SRCCOPY);
	}

	int clrR = GetRValue (clrLine);
	int clrG = GetGValue (clrLine);
	int clrB = GetBValue (clrLine);
	int clrA = 255;

    if (exch)
    {
		COLORREF* pRow = pBits + (size.cy - (ix1 - rect.top) - 1) * size.cx + (iy1 - rect.left);
		*pRow = RGB (clrB * f1, clrG * f1, clrR * f1) | ((int)(clrA * f1) << 24);
		pRow++;
		*pRow = RGB (clrB * f2, clrG * f2, clrR * f2) | ((int)(clrA * f2) << 24);

		pRow = pBits + (size.cy - (ix2 - rect.top) - 1) * size.cx + (iy2 - rect.left);
		*pRow = RGB (clrB * f3, clrG * f3, clrR * f3) | ((int)(clrA * f3) << 24);
		pRow++;
		*pRow = RGB (clrB * f4, clrG * f4, clrR * f4) | ((int)(clrA * f4) << 24);
    }
    else
    {
		*(pBits + (size.cy - (iy1 - rect.top) - 1) * size.cx + (ix1 - rect.left)) =
			RGB (clrB * f1, clrG * f1, clrR * f1) | ((int)(clrA * f1) << 24);
		*(pBits + (size.cy - (iy1 - rect.top + 1) - 1) * size.cx + (ix1 - rect.left)) =
			RGB (clrB * f2, clrG * f2, clrR * f2) | ((int)(clrA * f2) << 24);

		*(pBits + (size.cy - (iy2 - rect.top) - 1) * size.cx + (ix2 - rect.left)) =
			RGB (clrB * f3, clrG * f3, clrR * f3) | ((int)(clrA * f3) << 24);
		*(pBits + (size.cy - (iy2 - rect.top + 1) - 1) * size.cx + (ix2 - rect.left)) =
			RGB (clrB * f4, clrG * f4, clrR * f4) | ((int)(clrA * f4) << 24);
    }

    for(int x = ix1 + 1; x <= ix2 - 1; x++)
    {
		double f = frac (yf);

		int y = (int)floor(yf);

		int B = (int)(clrB * f);
		int G = (int)(clrG * f);
		int R = (int)(clrR * f);
		int A = (int)(clrA * f);

        if (exch)
        {
			COLORREF* pRow = pBits + (size.cy - (x - rect.top) - 1) * size.cx + (y - rect.left);
			*pRow = RGB ((clrB - B), (clrG - G), (clrR - R)) | ((clrA - A) << 24);
			pRow++;
			*pRow = RGB (B, G, R) | (A << 24);
        }
        else
        {
			*(pBits + (size.cy - (y - rect.top) - 1) * size.cx + (x - rect.left)) = 
				RGB ((clrB - B), (clrG - G), (clrR - R)) | ((clrA - A) << 24);
			*(pBits + (size.cy - (y - rect.top + 1) - 1) * size.cx + (x - rect.left)) = 
				RGB (B, G, R) | (A << 24);
        }

        yf = yf + grad;
    }

	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------

	DrawAlpha (&m_dc, rect, &dcMem, CRect (CPoint (0, 0), size));

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);
}

void CMyDrawManager::DrawEllipse (const CRect& rect, COLORREF clrFill, COLORREF clrLine)
{
	if (clrFill == -1 && clrLine == -1)
	{
		ASSERT (FALSE);
		return;
	}

	CRect rt (rect);
	rt.NormalizeRect ();

	CSize size (rt.Size ());
	if (size.cx == 0 || size.cy == 0)
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, size.cx, size.cy))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (size, (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	dcMem.SelectObject (hmbpDib);

	ALPHABLEND m_pfAlphaBlend = NULL;
	HMODULE hT = LoadLibrary (_T("msimg32.dll"));
	if(NULL!=hT)
	{
		m_pfAlphaBlend = (ALPHABLEND)::GetProcAddress (hT, "AlphaBlend");
	}
	if (m_pfAlphaBlend == NULL || globalData.bIsWindows9x)
	{
		dcMem.BitBlt (0, 0, size.cx, size.cy, &m_dc, rt.left, rt.top, SRCCOPY);
	}

	if (clrLine == -1)
	{
		clrLine = clrFill;
	}

	int brdR = GetRValue (clrLine);
	int brdG = GetGValue (clrLine);
	int brdB = GetBValue (clrLine);

	int filR = GetRValue (clrFill);
	int filG = GetGValue (clrFill);
	int filB = GetBValue (clrFill);

	BOOL bFill = clrFill != -1;
	if (bFill)
	{
		clrFill = RGB (filB, filG, filR) | 0xFF000000;
	}

	int R, G, B, A;
	COLORREF clrN, clrI;

	bool exch = false;
	double a;
	double b;
	double cx;
	double cy;

	{
		double x1 = 0;
		double x2 = size.cx - 1;
		double y1 = 0;
		double y2 = size.cy - 1;

		if (x2 < x1 )
		{
			double t  = x1;
			x1 = x2;
			x2 = t;
		}

		if (y2 < y1)
		{
			double t  = y1;
			y1 = y2;
			y2 = t;
		}

		if (y2 - y1 <= x2 - x1)
		{
			exch = true;
			double t = x1;
			x1 = y1;
			y1 = t;

			t = x2;
			x2 = y2;
			y2 = t;
		}

		a  = (x2 - x1) / 2.0;
		b  = (y2 - y1) / 2.0;
		cx = (x1 + x2) / 2.0;
		cy = (y1 + y2) / 2.0;
	}

	if (bFill)
	{
		int i1 = (int)ceil (cx - a);
		int i2 = (int)floor (cx + a);
		for(int ix = i1; ix <= i2; ix++)
		{
			double dist = 1.0 - sqr((ix - cx) / a);
			if(dist < 0)
			{
				continue;
			}

			double y = b * sqrt(dist);

			if (!exch)
			{
				int y1 = (int)ceil(cy - y);
				int y2 = (int)floor(cy + y);
				COLORREF* pRow = pBits + y1 * size.cx + ix;
				for(int i = y1; i <= y2; i++)
				{
					*pRow = clrFill;
					pRow += size.cx;
				}
			}
			else
			{
				int x1 = (int)ceil(cy - y);
				int x2 = (int)floor(cy + y);
				COLORREF* pRow = pBits + ix * size.cx + x1;
				for(int i = x1; i <= x2; i++)
				{
					*pRow = clrFill;
					pRow++;
				}
			}
		}
	}


	double t  = a * a / sqrt(a * a + b * b);
	int i1 = (int)floor (cx - t);
	int i2 = (int)ceil (cx + t);

	for(int ix = i1; ix <= i2; ix++)
	{
		double dist = 1.0 - sqr((ix - cx) / a);
		if(dist < 0)
		{
			continue;
		}

		double y  = b * sqrt(dist);
		int iy = (int)ceil(cy + y);
		double f  = iy - cy - y;

		B = (int)(brdB * f);
		G = (int)(brdG * f);
		R = (int)(brdR * f);
		A = (int)(255  * f);

		if (bFill)
		{
			double fi = 1.0 - f;
			clrN = RGB (filB * fi + B, filG * fi + G, filR * fi + R) | 0xFF000000;
		}
		else
		{
			clrN = RGB (B, G, R) | (A << 24);
		}

		clrI = RGB ((brdB - B), (brdG - G), (brdR - R)) | ((255 - A) << 24);

		if (!exch)
		{
			*(pBits + iy * size.cx + ix) = clrI;
			*(pBits + (iy - 1) * size.cx + ix) = clrN;
		}
		else
		{
			*(pBits + ix * size.cx + iy) = clrI;
			*(pBits + ix * size.cx + iy - 1) = clrN;
		}

		iy = (int)floor (cy - y);
		f  = cy - y - iy;

		B = (int)(brdB * f);
		G = (int)(brdG * f);
		R = (int)(brdR * f);
		A = (int)(255  * f);

		if (bFill)
		{
			double fi = 1.0 - f;
			clrN = RGB (filB * fi + B, filG * fi + G, filR * fi + R) | 0xFF000000;
		}
		else
		{
			clrN = RGB (B, G, R) | (A << 24);
		}
		
		clrI = RGB ((brdB - B), (brdG - G), (brdR - R)) | ((255 - A) << 24);

		if (!exch)
		{
			*(pBits + iy * size.cx + ix) = clrI;
			*(pBits + (iy + 1) * size.cx + ix) = clrN;
		}
		else
		{
			*(pBits + ix * size.cx + iy) = clrI;
			*(pBits + ix * size.cx + iy + 1) = clrN;
		}
	}

	t  = b * b / sqrt(a * a + b * b);
	i1 = (int)ceil (cy - t);
	i2 = (int)floor (cy + t);

	for(int iy = i1; iy <= i2; iy++)
	{
		double dist = 1.0 - sqr((iy - cy) / b);
		if(dist < 0)
		{
			continue;
		}

		double x  = a * sqrt(dist);
		int ix = (int)floor(cx - x);
		double f  = cx - x - ix;

		B = (int)(brdB * f);
		G = (int)(brdG * f);
		R = (int)(brdR * f);
		A = (int)(255  * f);

		if (bFill)
		{
			double fi = 1.0 - f;
			clrN = RGB (filB * fi + B, filG * fi + G, filR * fi + R) | 0xFF000000;
		}
		else
		{
			clrN = RGB (B, G, R) | (A << 24);
		}

		clrI = RGB ((brdB - B), (brdG - G), (brdR - R)) | ((255 - A) << 24);

		if (!exch)
		{
			*(pBits + iy * size.cx + ix) = clrI;
			*(pBits + iy * size.cx + ix + 1) = clrN;
		}
		else
		{
			*(pBits + ix * size.cx + iy) = clrI;
			*(pBits + (ix + 1) * size.cx + iy) = clrN;
		}

		ix = (int)ceil(cx + x);
		f  = ix - cx - x;

		B = (int)(brdB * f);
		G = (int)(brdG * f);
		R = (int)(brdR * f);
		A = (int)(255  * f);
		
		if (bFill)
		{
			double fi = 1.0 - f;
			clrN = RGB (filB * fi + B, filG * fi + G, filR * fi + R) | 0xFF000000;
		}
		else
		{
			clrN = RGB (B, G, R) | (A << 24);
		}

		clrI = RGB ((brdB - B), (brdG - G), (brdR - R)) | ((255 - A) << 24);

		if (!exch)
		{
			*(pBits + iy * size.cx + ix) = clrI;
			*(pBits + iy * size.cx + ix - 1) = clrN;
		}
		else
		{
			*(pBits + ix * size.cx + iy) = clrI;
			*(pBits + (ix - 1) * size.cx + iy) = clrN;
		}
	}

	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------

	DrawAlpha (&m_dc, rt, &dcMem, CRect (CPoint (0, 0), size));

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);
}

void CMyDrawManager::DrawRect (const CRect& rect, COLORREF clrFill, COLORREF clrLine)
{
	if (clrFill == -1 && clrLine == -1)
	{
		ASSERT (FALSE);
		return;
	}

	CRect rt (rect);
	rt.NormalizeRect ();

	CSize size (rt.Size ());
	if (size.cx == 0 || size.cy == 0)
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Copy screen content into the memory bitmap:
	//--------------------------------------------
	CDC dcMem;
	if (!dcMem.CreateCompatibleDC (&m_dc))
	{
		ASSERT (FALSE);
		return;
	}

	//--------------------------------------------
	// Gets the whole menu and changes the shadow.
	//--------------------------------------------
	CBitmap	bmpMem;
	if (!bmpMem.CreateCompatibleBitmap (&m_dc, size.cx, size.cy))
	{
		ASSERT (FALSE);
		return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
	ASSERT (pOldBmp != NULL);

	COLORREF* pBits;
	HBITMAP hmbpDib = CreateBitmap_32 (size, (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	dcMem.SelectObject (hmbpDib);

	ALPHABLEND m_pfAlphaBlend = NULL;
	HMODULE hT = LoadLibrary (_T("msimg32.dll"));
	if(NULL!=hT)
	{
		m_pfAlphaBlend = (ALPHABLEND)::GetProcAddress (hT, "AlphaBlend");
	}
	if (m_pfAlphaBlend == NULL || globalData.bIsWindows9x)
	{
		dcMem.BitBlt (0, 0, size.cx, size.cy, &m_dc, rt.left, rt.top, SRCCOPY);
	}

	int xB = 0;
	int xE = size.cx;
	int yB = 1;
	int yE = size.cy;

	if (clrLine != -1)
	{
		COLORREF clr = RGB (GetBValue (clrLine),
							GetGValue (clrLine),
							GetRValue (clrLine)) | 0xFF000000;

		for (int x = 0; x < size.cx; x++)
		{
			*pBits = clr;
			pBits++;
		}

		if (1 < size.cy)
		{
			memcpy((LPVOID)(pBits + (size.cy - 2) * size.cx), (LPCVOID)(pBits - size.cx), size.cx * sizeof(COLORREF));

			if (2 < size.cy)
			{
				*pBits = clr;
				if (2 <= size.cx)
				{
					*(pBits + size.cx - 1) = clr;
				}
				pBits++;
			}
		}

		xB++;
		xE--;
		yB++;
		yE--;
	}

	COLORREF clr = clrFill == -1
			? 0
			: RGB (GetBValue (clrFill),
					GetGValue (clrFill),
					GetRValue (clrFill)) | 0xFF000000;

	if (yB <= yE)
	{
		for (int x = xB; x < xE; x++)
		{
			*pBits = clr;
			pBits++;
		}

		if (xB < xE && clrLine != -1)
		{
			pBits++;
		}
	}

	for (int y = yB; y < yE; y++)
	{
		memcpy((LPVOID)(pBits), (LPCVOID)(pBits - size.cx), size.cx * sizeof(COLORREF));
		pBits += size.cx;
	}

	//--------------------------------
	// Copy bitmap back to the screen:
	//--------------------------------

	if (clrFill != -1)
	{
		m_dc.BitBlt (rt.left, rt.top, size.cx, size.cy, &dcMem, 0, 0, SRCCOPY);
	}
	else
	{
		DrawAlpha (&m_dc, rt, &dcMem, CRect (CPoint (0, 0), size));
	}

	dcMem.SelectObject (pOldBmp);
	DeleteObject (hmbpDib);
}

inline void CMyDrawManager::SetAlphaPixel (COLORREF* pBits, 
											 CRect rect, int x, int y, 
											 int percent, int m_iShadowSize,
											 COLORREF clrBase,
											 BOOL bIsRight)
{
	// Our direct bitmap access swapped the y coordinate...
	y = (rect.Height()+m_iShadowSize)- y;

	COLORREF* pColor = (COLORREF*) (bIsRight ? 
		(pBits + (rect.Width () + m_iShadowSize) * (y + 1) - x) : 
		(pBits + (rect.Width () + m_iShadowSize) * y + x));

	*pColor = PixelAlpha (*pColor, percent);

	if (clrBase == (COLORREF)-1)
	{
		return;
	}

	*pColor = RGB (	min (255, (3 * GetRValue (*pColor) + GetBValue (clrBase)) / 4),
					min (255, (3 * GetGValue (*pColor) + GetGValue (clrBase)) / 4),
					min (255, (3 * GetBValue (*pColor) + GetRValue (clrBase)) / 4));
}

COLORREF CMyDrawManager::PixelAlpha (COLORREF srcPixel, int percent)
{
	// My formula for calculating the transpareny is as
	// follows (for each single color):
	//
	//							   percent
	// destPixel = sourcePixel * ( ------- )
	//                               100
	//
	// This is not real alpha blending, as it only modifies the brightness,
	// but not the color (a real alpha blending had to mix the source and
	// destination pixels, e.g. mixing green and red makes yellow).
	// For our nice "menu" shadows its good enough.

	COLORREF clrFinal = RGB ( min (255, (GetRValue (srcPixel) * percent) / 100), 
							  min (255, (GetGValue (srcPixel) * percent) / 100), 
							  min (255, (GetBValue (srcPixel) * percent) / 100));

//	TRACE ("%d %d %d\n", GetRValue (clrFinal), GetGValue (clrFinal), GetBValue (clrFinal));
	return (clrFinal);

}

static inline int AdjustChannel (int nValue, double nPercent)
{
	int nNewValue = (int) (.5 + nPercent * nValue);
	if (nValue == 0 && nPercent > 1.)
	{
		nNewValue = (int) (.5 + (nPercent - 1.) * 255);
	}

	return min (nNewValue, 255);
}

COLORREF CMyDrawManager::PixelAlpha (COLORREF srcPixel, double percentR, double percentG, double percentB)
{
	COLORREF clrFinal = RGB ( AdjustChannel (GetRValue (srcPixel), percentR), 
							  AdjustChannel (GetGValue (srcPixel), percentG), 
							  AdjustChannel (GetBValue (srcPixel), percentB));

	return (clrFinal);

}

// ==================================================================
// 
// FUNCTION :  PixelAlpha ()
// 
// * Description : Shades a color value with a specified percentage
// 
// * Author : [Guillaume Nodet]
// 
// * Returns : [COLORREF] - The result pixel
// 
// * Function parameters : 
// [srcPixel] - The source pixel
// [dstPixel] - The destination pixel
// [percent] -  Percentage (amount of shadow)
//
// ==================================================================
COLORREF CMyDrawManager::PixelAlpha (COLORREF srcPixel, COLORREF dstPixel, int percent)
{
	int ipercent = 100 - percent;
	COLORREF clrFinal = RGB ( (GetRValue (srcPixel) * percent + GetRValue (dstPixel) * ipercent) / 100, 
							  (GetGValue (srcPixel) * percent + GetGValue (dstPixel) * ipercent) / 100, 
							  (GetBValue (srcPixel) * percent + GetBValue (dstPixel) * ipercent) / 100);

	return (clrFinal);

}

void CMyDrawManager::SetPixel (COLORREF* pBits, int cx, int cy, int x, int y,
								COLORREF color)
{
	// Our direct bitmap access swapped the y coordinate...
	y = cy - y;

	COLORREF* pColor = (COLORREF*) (pBits + cx * y + x);
	*pColor = RGB (GetBValue(color), GetGValue(color), GetRValue(color));
}

//----------------------------------------------------------------------
// Conversion between the HSL (Hue, Saturation, and Luminosity) 
// and RBG color model.
//----------------------------------------------------------------------
// The conversion algorithms presented here come from the book by 
// Fundamentals of Interactive Computer Graphics by Foley and van Dam. 
// In the example code, HSL values are represented as floating point 
// number in the range 0 to 1. RGB tridrants use the Windows convention 
// of 0 to 255 of each element. 
//----------------------------------------------------------------------

double CMyDrawManager::HuetoRGB(double m1, double m2, double h )
{
	if( h < 0 ) h += 1.0;
	if( h > 1 ) h -= 1.0;
	if( 6.0*h < 1 )
		return (m1+(m2-m1)*h*6.0);
	if( 2.0*h < 1 )
		return m2;
	if( 3.0*h < 2.0 )
		return (m1+(m2-m1)*((2.0/3.0)-h)*6.0);
	return m1;
}

BYTE CMyDrawManager::HueToRGB(float rm1, float rm2, float rh)
{
	if (rh > 360.0f)
		rh -= 360.0f;
	else if (rh < 0.0f)
		rh += 360.0f;
	
	if (rh <  60.0f)
		rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;   
	else if (rh < 180.0f)
		rm1 = rm2;
	else if (rh < 240.0f)
		rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;      
	
	return static_cast<BYTE>(rm1 * 255);
}

COLORREF CMyDrawManager::HLStoRGB_ONE( double H, double L, double S )
{
	double r, g, b;
	double m1, m2;
	
	if(S==0) {
		r=g=b=L;
	} else {
		if(L <=0.5)
			m2 = L*(1.0+S);
		else
			m2 = L+S-L*S;
		m1 = 2.0*L-m2;
		r = HuetoRGB(m1, m2, H+1.0/3.0);
		g = HuetoRGB(m1, m2, H);
		b = HuetoRGB(m1, m2, H-1.0/3.0);
	}
	return RGB((BYTE)(r*255), (BYTE)(g*255), (BYTE)(b*255));
}

COLORREF CMyDrawManager::HLStoRGB_TWO( double H, double L, double S)
{
	WORD R, G, B; // RGB component values
	
	if (S == 0.0)
		R = G = B = unsigned char(L * 255.0);
	else
	{
		float rm1, rm2;
		
		if (L <= 0.5f)
			rm2 = (float)(L + L * S);
		else
			rm2 = (float)(L + S - L * S);
		
		rm1 = (float)(2.0f * L - rm2);
		
		R = HueToRGB(rm1, rm2, (float)(H + 120.0f));
		G = HueToRGB(rm1, rm2, (float)(H));
		B = HueToRGB(rm1, rm2, (float)(H - 120.0f));
	}
	
	return RGB(R, G, B);
}

void CMyDrawManager::RGBtoHSL( COLORREF rgb, double *H, double *S, double *L )
{   
	double delta;
	double r = (double)GetRValue(rgb)/255;
	double g = (double)GetGValue(rgb)/255;
	double b = (double)GetBValue(rgb)/255;   
	double cmax = max(r, max(g, b));
	double cmin = min(r, min(g, b));   
	*L=(cmax+cmin)/2.0;   
	
	if(cmax==cmin) 
	{
		*S = 0;      
		*H = 0; // it's really undefined   
	} 
	else 
	{
		if(*L < 0.5) 
			*S = (cmax-cmin)/(cmax+cmin);      
		else
			*S = (cmax-cmin)/(2.0-cmax-cmin);      
		
		delta = cmax - cmin;
		if(r==cmax) 
			*H = (g-b)/delta;      
		else if(g==cmax)
			*H = 2.0 +(b-r)/delta;
		else          
			*H=4.0+(r-g)/delta;
		*H /= 6.0; 
		if(*H < 0.0)
			*H += 1;  
	}
}

void CMyDrawManager::RGBtoHSV (COLORREF rgb, double *H, double *S, double *V)
// Algoritm by A. R. Smith 
{
	double r = (double) GetRValue (rgb) / 255;
	double g = (double) GetGValue (rgb) / 255;
	double b = (double) GetBValue (rgb) / 255;

	double dblMin = min (r, min (g, b));
	double dblMax = max (r, max (g, b));

	*V = dblMax;				// v
	double delta = dblMax - dblMin;

	if( dblMax != 0 )
		*S = delta / dblMax;		// s
	else {
		// r = g = b = 0		// s = 0, v is undefined
		*S = 0;
		*H = -1;
		return;
	}

	if (delta == 0.)
	{
		*H = 1;
	}
	else
	{
		if (r == dblMax)
			*H = (g - b) / delta;		// between yellow & magenta
		else if( g == dblMax )
			*H = 2 + ( b - r ) / delta;	// between cyan & yellow
		else
			*H = 4 + ( r - g ) / delta;	// between magenta & cyan
	}

	*H *= 60;				// degrees

	if (*H < 0)
		*H += 360;
}

COLORREF CMyDrawManager::HSVtoRGB (double h, double s, double v)
// Algoritm by A. R. Smith
{
	int i;
	double f, p, q, t;
	double r, g, b;

	if( s == 0 ) 
	{
		// achromatic (grey)
		r = g = b = v;
	}
	else
	{
		h /= 60;			// sector 0 to 5
		i = (int) floor( h );
		f = h - i;			// factorial part of h
		p = v * ( 1 - s );
		q = v * ( 1 - s * f );
		t = v * ( 1 - s * ( 1 - f ) );

		switch( i ) 
		{
		case 0:
			r = v;
			g = t;
			b = p;
			break;
		case 1:
			r = q;
			g = v;
			b = p;
			break;
		case 2:
			r = p;
			g = v;
			b = t;
			break;
		case 3:
			r = p;
			g = q;
			b = v;
			break;
		case 4:
			r = t;
			g = p;
			b = v;
			break;
		default:		// case 5:
			r = v;
			g = p;
			b = q;
			break;
		}
	}

	return RGB (
		(int) (.5 + r * 255),
		(int) (.5 + g * 255),
		(int) (.5 + b * 255));
}

COLORREF CMyDrawManager::SmartMixColors (COLORREF color1, COLORREF color2,
		double dblLumRatio, int k1, int k2)
{
	ASSERT (k1 >= 0);
	ASSERT (k2 >= 0);

	if (k1 + k2 == 0)
	{
		ASSERT (FALSE);
		return RGB (0, 0, 0);
	}

	COLORREF color = RGB (
		(GetRValue (color1) * k1 + GetRValue (color2) * k2) / (k1 + k2),
		(GetGValue (color1) * k1 + GetGValue (color2) * k2) / (k1 + k2),
		(GetBValue (color1) * k1 + GetBValue (color2) * k2) / (k1 + k2));

	double h1, s1, v1;
	RGBtoHSV (color, &h1, &s1, &v1);

	double h2, s2, v2;
	RGBtoHSV (color2, &h2, &s2, &v2);

	v1 = v2;
	s1 = (s1 *  k1 + s2 *  k2) /  (k1 + k2);

	color = HSVtoRGB (h1, s1, v1);

	if (dblLumRatio != 1.)
	{
		double H, S, L;
		RGBtoHSL (color, &H, &S, &L);

		color = HLStoRGB_ONE (H, min (1., L * dblLumRatio), S);
	}

	return color;
}

COLORREF CMyDrawManager::MixColors (COLORREF clr1, COLORREF clr2, double dblRatio)
{
    ASSERT (dblRatio > 0.0f && dblRatio <= 1.0f);

    return RGB (
        GetRValue(clr1) + dblRatio * (GetRValue(clr2) - GetRValue(clr1)),
        GetGValue(clr1) + dblRatio * (GetGValue(clr2) - GetGValue(clr1)),
        GetBValue(clr1) + dblRatio * (GetBValue(clr2) - GetBValue(clr1))
        );
} 

void CMyDrawManager::DrawAlpha (CDC* pDstDC, const CRect& rectDst, CDC* pSrcDC, const CRect& rectSrc,
								  BYTE nOpacity)
{
	BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 
		nOpacity, 1 /*AC_SRC_ALPHA*/};

	ALPHABLEND m_pfAlphaBlend = NULL;
	HMODULE hT = LoadLibrary (_T("msimg32.dll"));
	if(NULL!=hT)
	{
		m_pfAlphaBlend = (ALPHABLEND)::GetProcAddress (hT, "AlphaBlend");
	}
	if (m_pfAlphaBlend != NULL && !globalData.bIsWindows9x)
	{
		(*m_pfAlphaBlend) (pDstDC->m_hDC, 
			rectDst.left, rectDst.top,
			rectDst.Width(), rectDst.Height(), 
			pSrcDC->m_hDC, rectSrc.left, rectSrc.top,
			rectSrc.Width(), rectSrc.Height(), 
			pixelblend);
	}
	else
	{
		if (rectSrc.Width () != rectDst.Width () ||
			rectSrc.Height () != rectDst.Height ())
		{
			pDstDC->StretchBlt(rectDst.left, rectDst.top,
				rectDst.Width(), rectDst.Height(), 
				pSrcDC, rectSrc.left, rectSrc.top,
				rectSrc.Width(), rectSrc.Height(), SRCCOPY);
		}
		else
		{
			pDstDC->BitBlt (rectDst.left, rectDst.top, rectDst.Width(), rectDst.Height(), 
				pSrcDC, rectSrc.left, rectSrc.top, SRCCOPY);
		}
	}
}
//***********************************************************************************************************
void CMyDrawManager::FillAlpha (const CRect& rect, BYTE bValue/* = 255*/)
{
	const int cx = rect.Width ();
	const int cy = rect.Height ();

	COLORREF* pBits = NULL;
	HBITMAP hmbpDib = CreateBitmap_32 (CSize (cx, cy), (LPVOID*)&pBits);

	if (hmbpDib == NULL || pBits == NULL)
	{
		ASSERT (FALSE);
		return;
	}

	CDC dcMem;
	dcMem.CreateCompatibleDC (&m_dc);

	HBITMAP hbmpOld = (HBITMAP) dcMem.SelectObject (hmbpDib);

	dcMem.BitBlt (0, 0, cx, cy, &m_dc, rect.left, rect.top, SRCCOPY);

	const DWORD dwMask = (bValue << 24) & 0xFF000000;

	for (int i = 0; i < cx * cy; i++)
	{
		*pBits |= dwMask;
		pBits++;
	}

	m_dc.BitBlt (rect.left, rect.top, cx, cy, &dcMem, 0, 0, SRCCOPY);

	dcMem.SelectObject (hbmpOld);
	DeleteObject (hmbpDib);
}
//***********************************************************************************************************
void CMyDrawManager::DrawRotated (CRect rect, CDC& dcSrc, BOOL bClockWise)
{
	const int cx = rect.Width ();
	const int cy = rect.Height ();

	if (cx <= 0 || cy <= 0)
	{
		return;
	}

	for (int y = 0; y <= cy; y++)
	{
		for (int x = 0; x <= cx; x++)
		{
			int xSrc = y;
			int ySrc = bClockWise ? (cx - x - 1) : x;

			m_dc.SetPixel (rect.left + x, rect.top + y, dcSrc.GetPixel (xSrc, ySrc));
		}
	}
}

HBITMAP CMyDrawManager::PrepareShadowMask (int nDepth,
											 COLORREF clrBase,
                                             int iMinBrightness/* = 0*/, int iMaxBrightness/* = 100*/)
{
	if (nDepth == 0)
	{
		return NULL;
	}

	int nSize     = nDepth < 3 ? 3 : nDepth;
	int nDestSize = nSize * 2 + 1;

	LPBYTE lpBits = NULL;
	HBITMAP hBitmap = CreateBitmap_32 (CSize (nDestSize, nDestSize), (void**)&lpBits);

	if (hBitmap == NULL || lpBits == NULL)
	{
		return NULL;
	}

	// Create mask
	int nDestLength = nDestSize * nDestSize;
	double* mask = new double[nDestLength];

	double dispersion = 1.0;
	double minValue   = iMinBrightness / 100.0;
	double maxValue   = iMaxBrightness / 100.0;
	double delta      = maxValue - minValue;

	long size2      = nDestSize / 2;
	double size2S   = nDestSize * nDestSize / 4.0;

	double* pMask = mask;

	for(long y = -size2; y <= size2; y++)
	{
		double y2 = y * y;

		for(long x = -size2; x <= size2; x++)
		{
			double d = y2 + x * x;
			double e = 0.0;

			if(d <= size2S)
			{
				e = min (maxValue, max (exp (-(d / size2S) / dispersion * 2.0) * delta + minValue, minValue));
			}

			*pMask++ = e;
		}
	}

	BYTE r = (BYTE) (GetRValue (clrBase) / 4);
	BYTE g = (BYTE) (GetGValue (clrBase) / 4);
	BYTE b = (BYTE) (GetBValue (clrBase) / 4);

	pMask = mask;
	LPRGBQUAD pQuad = (LPRGBQUAD)lpBits;
	for (int i = 0; i < nDestLength; i++)
	{
		pQuad->rgbRed      = (BYTE)(*pMask * r);
		pQuad->rgbGreen    = (BYTE)(*pMask * g);
		pQuad->rgbBlue     = (BYTE)(*pMask * b);
		pQuad->rgbReserved = (BYTE)(*pMask * 255);

		pMask++;
		pQuad++;
	}

	if (mask != NULL)
	{
		delete [] mask;
	}

	return hBitmap;
}

/************************************************************************/
/* CMyMemDC                                                             */
/************************************************************************/
CMyMemDC::CMyMemDC (CDC& dc, CWnd* pWnd, BYTE alpha) :
	m_dc			(dc),
	m_bMemDC		(FALSE),
	m_hBufferedPaint(NULL),
	m_pOldBmp		(NULL),
	m_alpha			(alpha)
{
	ASSERT_VALID(pWnd);

	pWnd->GetClientRect (m_rect);

	m_rect.right += pWnd->GetScrollPos (SB_HORZ);
	m_rect.bottom += pWnd->GetScrollPos (SB_VERT);

	if (globalData.m_pfBeginBufferedPaint != NULL && globalData.m_pfEndBufferedPaint != NULL)
	{
		HDC hdcPaint = NULL;

		m_hBufferedPaint = (*globalData.m_pfBeginBufferedPaint) 
			(dc.GetSafeHdc (), m_rect, MY_BPBF_TOPDOWNDIB, NULL, &hdcPaint);

		if (m_hBufferedPaint != NULL && hdcPaint != NULL)
		{
			m_bMemDC = TRUE;
			m_dcMem.Attach (hdcPaint);
		}
	}
	else
	{
		if (m_bUseMemoryDC &&
			m_dcMem.CreateCompatibleDC (&m_dc) &&
			m_bmp.CreateCompatibleBitmap (&m_dc, m_rect.Width (), m_rect.Height ()))
		{
			//-------------------------------------------------------------
			// Off-screen DC successfully created. Better paint to it then!
			//-------------------------------------------------------------
			m_bMemDC = TRUE;
			m_pOldBmp = m_dcMem.SelectObject (&m_bmp);
		}
	}
}

CMyMemDC::CMyMemDC(CDC& dc, const CRect& rect, BYTE alpha) :
	m_dc			(dc),
	m_bMemDC		(FALSE),
	m_hBufferedPaint(NULL),
	m_pOldBmp		(NULL),
	m_rect			(rect),
	m_alpha			(alpha)
{
	ASSERT(!m_rect.IsRectEmpty());

	if (globalData.m_pfBeginBufferedPaint != NULL && globalData.m_pfEndBufferedPaint != NULL)
	{
		HDC hdcPaint = NULL;

		m_hBufferedPaint = (*globalData.m_pfBeginBufferedPaint) 
			(dc.GetSafeHdc (), m_rect, MY_BPBF_TOPDOWNDIB, NULL, &hdcPaint);

		if (m_hBufferedPaint != NULL && hdcPaint != NULL)
		{
			m_bMemDC = TRUE;
			m_dcMem.Attach (hdcPaint);
		}
	}
	else
	{
		if (m_bUseMemoryDC &&
			m_dcMem.CreateCompatibleDC (&m_dc) &&
			m_bmp.CreateCompatibleBitmap (&m_dc, m_rect.Width (), m_rect.Height ()))
		{
			//-------------------------------------------------------------
			// Off-screen DC successfully created. Better paint to it then!
			//-------------------------------------------------------------
			m_bMemDC = TRUE;
			m_pOldBmp = m_dcMem.SelectObject (&m_bmp);
		}
	}
}

CMyMemDC::~CMyMemDC()
{
	if (m_hBufferedPaint != NULL)
	{
		m_dcMem.Detach ();

		if (m_alpha != 0 && globalData.m_pfBufferedPaintSetAlpha != NULL)
		{
			(*globalData.m_pfBufferedPaintSetAlpha) (m_hBufferedPaint, NULL, m_alpha);
		}

		(*globalData.m_pfEndBufferedPaint) (m_hBufferedPaint, TRUE);
	}
	else if (m_bMemDC)
	{
		//--------------------------------------
		// Copy the results to the on-screen DC:
		//-------------------------------------- 
		CRect rectClip;
		int nClipType = m_dc.GetClipBox (rectClip);

		if (nClipType != NULLREGION)
		{
			if (nClipType != SIMPLEREGION)
			{
				rectClip = m_rect;
			}

			m_dc.BitBlt (rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(),
						   &m_dcMem, rectClip.left, rectClip.top, SRCCOPY);
		}

		m_dcMem.SelectObject (m_pOldBmp);
	}
}

static int CALLBACK FontFamalyProcFonts (const LOGFONT FAR* lplf,
									const TEXTMETRIC FAR* /*lptm*/,
									ULONG /*ulFontType*/,
									LPARAM lParam)
{
	ASSERT (lplf != NULL);
	ASSERT (lParam != NULL);

	CString strFont = lplf->lfFaceName;
	return strFont.CollateNoCase ((LPCTSTR) lParam) == 0 ? 0 : 1;
}
/////////////////////////////////////////////////////////////////////////////
// Cached system metrics, etc

MYGLOBAL_DATA globalData;

// Initialization code
MYGLOBAL_DATA::MYGLOBAL_DATA()
{
	//-----------------------
	// Detect the kind of OS:
	//-----------------------
	OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

	::GetVersionEx (&osvi);
	bIsWindowsNT4 = ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
					(osvi.dwMajorVersion < 5));

	bIsWindows9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);

	bIsOSAlphaBlendingSupport = (osvi.dwMajorVersion > 4) ||
		((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0));

	if (bIsWindowsNT4)
	{
		bIsOSAlphaBlendingSupport = FALSE;
	}

	bIsRemoteSession = FALSE;

	if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
		(osvi.dwMajorVersion >= 5))
	{
		bIsRemoteSession = FALSE/*GetSystemMetrics (0x1000 / * SM_REMOTESESSION * /)*/;
	}

	bIsWindowsVista = (osvi.dwMajorVersion >= 6);
	bDisableAero = FALSE;

	m_bIsRibbonImageScale = TRUE;

	//---------------------------------------------------------
	// Cached system values (updated in CWnd::OnSysColorChange)
	//---------------------------------------------------------
	hbrBtnShadow = NULL;
	hbrBtnHilite = NULL;
	hbrWindow = NULL;

	UpdateSysColors();

	m_hinstUXThemeDLL = LoadLibrary (_T("UxTheme.dll"));
	if (m_hinstUXThemeDLL != NULL)
	{
		m_pfDrawThemeBackground = 
			(MY_DRAWTHEMEPARENTBACKGROUND)::GetProcAddress (m_hinstUXThemeDLL, "DrawThemeParentBackground");

		m_pfDrawThemeTextEx =
			(MY_DRAWTHEMETEXTEX)::GetProcAddress (m_hinstUXThemeDLL, "DrawThemeTextEx");

		m_pfDrawThemeIcon = 
			(MY_DRAWTHEMEICON)::GetProcAddress (m_hinstUXThemeDLL, "DrawThemeIcon");

		m_pfBeginBufferedPaint =
			(MY_BEGINBUFFEREDPAINT)::GetProcAddress (m_hinstUXThemeDLL, "BeginBufferedPaint");

		m_pfBufferedPaintSetAlpha =
			(MY_BUFFEREDPAINTSETALPHA)::GetProcAddress (m_hinstUXThemeDLL, "BufferedPaintSetAlpha");

		m_pfEndBufferedPaint =
			(MY_ENDBUFFEREDPAINT)::GetProcAddress (m_hinstUXThemeDLL, "EndBufferedPaint");
	}
	else
	{
		m_pfDrawThemeBackground = NULL;
		m_pfDrawThemeTextEx = NULL;
		m_pfDrawThemeIcon = NULL;
		m_pfBeginBufferedPaint = NULL;
		m_pfBufferedPaintSetAlpha = NULL;
		m_pfEndBufferedPaint = NULL;
	}

	m_hinstUser32 = LoadLibrary (_T("USER32.DLL"));

	if (!bIsOSAlphaBlendingSupport)
	{
		m_pfSetLayeredWindowAttributes = NULL;
		m_pfUpdateLayeredWindow = NULL;
	}
	else
	{
		if (m_hinstUser32 == NULL)
		{
			ASSERT (FALSE);
		}
		else
		{
			m_pfSetLayeredWindowAttributes = 
				(SETLAYEATTRIB)::GetProcAddress (
					m_hinstUser32, "SetLayeredWindowAttributes");
			m_pfUpdateLayeredWindow = 
				(UPDATELAYEREDWINDOW)::GetProcAddress (
					m_hinstUser32, "UpdateLayeredWindow");
		}
	}

	m_hinstDwmapiDLL = LoadLibrary (_T("dwmapi.dll"));
	if (m_hinstDwmapiDLL != NULL)
	{
		m_pfDwmExtendFrameIntoClientArea = 
			(MY_DWMEXTENDFRAMEINTOCLIENTAREA)::GetProcAddress (m_hinstDwmapiDLL, "DwmExtendFrameIntoClientArea");

		m_pfDwmDefWindowProc = 
			(MY_DWMDEFWINDOWPROC) ::GetProcAddress (m_hinstDwmapiDLL, "DwmDefWindowProc");

		m_pfDwmIsCompositionEnabled =
			(MY_DWMISCOMPOSITIONENABLED)::GetProcAddress (m_hinstDwmapiDLL, "DwmIsCompositionEnabled");
	}
	else
	{
		m_pfDwmExtendFrameIntoClientArea = NULL;
		m_pfDwmDefWindowProc = NULL;
		m_pfDwmIsCompositionEnabled = NULL;
	}

	m_hcurStretch = NULL;
	m_hcurStretchVert = NULL;
	m_hcurHand = NULL;
	m_hcurSizeAll = NULL;
	m_hiconTool = NULL;
	m_hiconLink = NULL;
	m_hiconColors = NULL;
	m_hcurMoveTab = NULL;
	m_hcurNoMoveTab = NULL;
	m_hcurSelectRow = NULL;

	m_bUseSystemFont = FALSE;
	m_bInSettingsChange = FALSE;

	UpdateFonts();
	OnSettingChange ();

	m_bIsRTL = FALSE;

	//------------------
	// Small icon sizes:
	//------------------
	m_nDragFrameThiknessFloat = 4;  // pixels
	m_nDragFrameThiknessDock = 3;   // pixels

	m_nAutoHideToolBarSpacing = 14; // pixels
	m_nAutoHideToolBarMargin  = 4;  // pixels

	m_nCoveredMainWndClientAreaPercent = 50; // percents

	m_nMaxToolTipWidth = -1;
	m_bIsBlackHighContrast = FALSE;
	m_bIsWhiteHighContrast = FALSE;

	m_bUseBuiltIn32BitIcons = TRUE;
	m_bUseVisualManagerInBuiltInDialogs = FALSE;

	m_dwComCtlVersion = (DWORD)-1;
}
//*******************************************************************************************
MYGLOBAL_DATA::~MYGLOBAL_DATA()
{
	CleanUp ();
}
//************************************************************************************
void MYGLOBAL_DATA::UpdateFonts()
{
	CWindowDC dc (NULL);
	m_dblRibbonImageScale = dc.GetDeviceCaps(LOGPIXELSX) / 96.0f;

	if (m_dblRibbonImageScale > 1. && m_dblRibbonImageScale < 1.1)
	{
		m_dblRibbonImageScale = 1.;
	}

	if (fontRegular.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontRegular.Detach ());
	}

	if (fontTooltip.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontTooltip.Detach ());
	}

	if (fontBold.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontBold.Detach ());
	}

	if (fontDefaultGUIBold.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontDefaultGUIBold.Detach ());
	}

	if (fontUnderline.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontUnderline.Detach ());
	}

	if (fontDefaultGUIUnderline.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontDefaultGUIUnderline.Detach ());
	}

	if (fontVert.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontVert.Detach ());
	}

	if (fontVertCaption.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontVertCaption.Detach ());
	}

	if (fontMarlett.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontMarlett.Detach ());
	}

	if (fontSmall.GetSafeHandle () != NULL)
	{
		::DeleteObject (fontSmall.Detach ());
	}

	//------------------
	// Initialize fonts:
	//------------------
	NONCLIENTMETRICS info;
	GetNonClientMetrics (info);

	LOGFONT lf;
	memset (&lf, 0, sizeof (LOGFONT));

	lf.lfCharSet = (BYTE) GetTextCharsetInfo (dc.GetSafeHdc (), NULL, 0);

	lf.lfHeight = info.lfMenuFont.lfHeight;
	lf.lfWeight = info.lfMenuFont.lfWeight;
	lf.lfItalic = info.lfMenuFont.lfItalic;

	//------------------
	// Adjust font size:
	//------------------
	int nFontHeight = lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight;
	if (nFontHeight <= 12)
	{
		nFontHeight = 11;
	}
	else
	{
		nFontHeight--;
	}

	lf.lfHeight = (lf.lfHeight < 0) ? -nFontHeight : nFontHeight;

	lstrcpy (lf.lfFaceName, info.lfMenuFont.lfFaceName);

	//-------------------------------------
	// 	Check if we should use system font:
	//-------------------------------------
	BOOL fUseSystemFont = m_bUseSystemFont || (info.lfMenuFont.lfCharSet > SYMBOL_CHARSET);
	if (!fUseSystemFont)
	{
		//----------------------------------
		// Check for "Tahoma" font existance:
		//----------------------------------
		if (::EnumFontFamilies (dc.GetSafeHdc (), NULL, FontFamalyProcFonts, 
			(LPARAM)(LPCTSTR) strOffice2007FontName) == 0)
		{
			//--------------------------------
			// Found! Use MS Office 2007 font!
			//--------------------------------
			lstrcpy (lf.lfFaceName, strOffice2007FontName);
			lf.lfQuality = 5 /*CLEARTYPE_QUALITY*/;
		}
		else if (::EnumFontFamilies (dc.GetSafeHdc (), NULL, FontFamalyProcFonts, 
			(LPARAM)(LPCTSTR) strOfficeFontName) == 0)
		{
			//---------------------------
			// Found! Use MS Office font!
			//---------------------------
			lstrcpy (lf.lfFaceName, strOfficeFontName);
		}
		else
		{
			//-----------------------------
			// Not found. Use default font:
			//-----------------------------
			lstrcpy (lf.lfFaceName, strDefaultFontName);
		}
	}

	fontRegular.CreateFontIndirect (&lf);

	//-------------------
	// Create small font:
	//-------------------
	LONG lfHeightSaved = lf.lfHeight;

	lf.lfHeight = (long) ((1. + abs (lf.lfHeight)) * 2 / 3);
	if (lfHeightSaved < 0)
	{
		lf.lfHeight = -lf.lfHeight;
	}

	fontSmall.CreateFontIndirect (&lf);

	lf.lfHeight = lfHeightSaved;

	//---------------------
	// Create tooltip font:
	//---------------------
	NONCLIENTMETRICS ncm;
	GetNonClientMetrics (ncm);

	lf.lfItalic = ncm.lfStatusFont.lfItalic;
	lf.lfWeight = ncm.lfStatusFont.lfWeight;
	fontTooltip.CreateFontIndirect (&lf);

	lf.lfItalic = info.lfMenuFont.lfItalic;
	lf.lfWeight = info.lfMenuFont.lfWeight;

	//-------------------------
	// Create "underline" font:
	//-------------------------
	lf.lfUnderline = TRUE;
	fontUnderline.CreateFontIndirect (&lf);
	lf.lfUnderline = FALSE;

	//------------------
	// Create bold font:
	//------------------
	lf.lfWeight = FW_BOLD;
	fontBold.CreateFontIndirect (&lf);

	//---------------------
	// Create Marlett font:
	//---------------------
	BYTE bCharSet = lf.lfCharSet;
	lf.lfWeight = info.lfMenuFont.lfWeight;
	lf.lfCharSet = SYMBOL_CHARSET;
	lf.lfWeight = 0;
	lf.lfHeight = ::GetSystemMetrics (SM_CYMENUCHECK) - 1;
	lstrcpy (lf.lfFaceName, strMarlettFontName);

	fontMarlett.CreateFontIndirect (&lf);

	lf.lfCharSet = bCharSet;	// Restore charset

	//----------------------
	// Create vertical font:
	//----------------------
	CFont font;
	if (font.CreateStockObject (DEFAULT_GUI_FONT))
	{
		if (font.GetLogFont (&lf) != 0)
		{
			lf.lfOrientation = 900;
			lf.lfEscapement = 2700;

			lf.lfHeight = info.lfMenuFont.lfHeight;
			lf.lfWeight = info.lfMenuFont.lfWeight;
			lf.lfItalic = info.lfMenuFont.lfItalic;
			
			lstrcpy (lf.lfFaceName, strVertFontName);

			fontVert.CreateFontIndirect (&lf);

			lf.lfEscapement = 900;
			fontVertCaption.CreateFontIndirect (&lf);
		}
	}

	//----------------------------------------
	// Create dialog underline and bold fonts:
	//----------------------------------------
	CFont* pDefaultGUIFont = CFont::FromHandle ((HFONT) GetStockObject (DEFAULT_GUI_FONT));
	ASSERT_VALID (pDefaultGUIFont);
	pDefaultGUIFont->GetLogFont (&lf);

	lf.lfUnderline = TRUE;
	fontDefaultGUIUnderline.CreateFontIndirect (&lf);
	lf.lfUnderline = FALSE;

	lf.lfWeight = FW_BOLD;
	fontDefaultGUIBold.CreateFontIndirect (&lf);

	UpdateTextMetrics();
}
//*******************************************************************************************
static BOOL CALLBACK InfoEnumProc (	HMONITOR hMonitor, HDC /*hdcMonitor*/,
										LPRECT /*lprcMonitor*/, LPARAM dwData)
{
	CRect* pRect = (CRect*) dwData;

	MONITORINFO mi;
	mi.cbSize = sizeof (MONITORINFO);

	if (GetMonitorInfo (hMonitor, &mi))
	{
		CRect rectMon = mi.rcWork;

		pRect->left = min (pRect->left, rectMon.left);
		pRect->right = max (pRect->right, rectMon.right);
		pRect->top = min (pRect->top, rectMon.top);
		pRect->bottom = max (pRect->bottom, rectMon.bottom);
	}

	return TRUE;
}
//*******************************************************************************************
void MYGLOBAL_DATA::OnSettingChange ()
{
	m_bInSettingsChange = TRUE;

	m_sizeSmallIcon.cx	= ::GetSystemMetrics (SM_CXSMICON);
	m_sizeSmallIcon.cy	= ::GetSystemMetrics (SM_CYSMICON);

	m_rectVirtual.SetRectEmpty ();

	if (!EnumDisplayMonitors (NULL, NULL, InfoEnumProc, (LPARAM) &m_rectVirtual))
	{
		::SystemParametersInfo (SPI_GETWORKAREA, 0, &m_rectVirtual, 0);
	}

	//--------------------------------
	// Get system menu animation type:
	//--------------------------------
	m_bMenuAnimation = FALSE;
	m_bMenuFadeEffect = FALSE;

	OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

	::GetVersionEx (&osvi);

	if (!bIsRemoteSession && !bIsWindows9x && osvi.dwMajorVersion >= 5)	// Ignore Win 98/ME
	{
		::SystemParametersInfo (SPI_GETMENUANIMATION, 
								0, &m_bMenuAnimation, 0);

		if (m_bMenuAnimation)
		{
			::SystemParametersInfo (SPI_GETMENUFADE,
									0, &m_bMenuFadeEffect, 0);
		}
	}

	m_nShellAutohideBars = 0;

	if (!bIsWindows9x)
	{
		::SystemParametersInfo (SPI_GETMENUUNDERLINES, 0, &m_bSysUnderlineKeyboardShortcuts, 0);
	}
	else
	{
		m_bSysUnderlineKeyboardShortcuts = TRUE;
	}

	m_bUnderlineKeyboardShortcuts = m_bSysUnderlineKeyboardShortcuts;

	m_bInSettingsChange = FALSE;
}
//*******************************************************************************************
void MYGLOBAL_DATA::UpdateSysColors()
{
	m_bIsBlackHighContrast = 
		::GetSysColor (COLOR_3DLIGHT) == RGB (255, 255, 255) &&
		::GetSysColor (COLOR_3DFACE) == RGB (0, 0, 0);

	m_bIsWhiteHighContrast = 
		::GetSysColor (COLOR_3DDKSHADOW) == RGB (0, 0, 0) &&
		::GetSysColor (COLOR_3DFACE) == RGB (255, 255, 255);

	CWindowDC dc (NULL);
	m_nBitsPerPixel = dc.GetDeviceCaps (BITSPIXEL);

	clrBarFace = clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
	clrBarShadow = clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
	clrBarDkShadow = clrBtnDkShadow = ::GetSysColor(COLOR_3DDKSHADOW);
	clrBarLight = clrBtnLight = ::GetSysColor(COLOR_3DLIGHT);
	clrBarHilite = clrBtnHilite = ::GetSysColor(COLOR_BTNHIGHLIGHT);
	clrBarText = clrBtnText = ::GetSysColor(COLOR_BTNTEXT);
	clrGrayedText = ::GetSysColor (COLOR_GRAYTEXT);
	clrWindowFrame = ::GetSysColor(COLOR_WINDOWFRAME);

	clrHilite = ::GetSysColor(COLOR_HIGHLIGHT);
	clrTextHilite = ::GetSysColor(COLOR_HIGHLIGHTTEXT);

	clrBarWindow = clrWindow = ::GetSysColor (COLOR_WINDOW);
	clrWindowText = ::GetSysColor (COLOR_WINDOWTEXT);

	clrCaptionText = ::GetSysColor (COLOR_CAPTIONTEXT);
	clrMenuText = ::GetSysColor (COLOR_MENUTEXT);

	clrActiveCaption = ::GetSysColor (COLOR_ACTIVECAPTION);
	clrInactiveCaption = ::GetSysColor (COLOR_INACTIVECAPTION);

	if (bIsWindowsNT4 || bIsWindows9x)
	{
		clrActiveCaptionGradient = clrActiveCaption;
		clrInactiveCaptionGradient = clrInactiveCaption;
	}
	else
	{
		clrActiveCaptionGradient = ::GetSysColor (27 /*COLOR_GRADIENTACTIVECAPTION*/);
		clrInactiveCaptionGradient = ::GetSysColor (28 /*COLOR_GRADIENTINACTIVECAPTION*/);
	}

	clrActiveBorder = ::GetSysColor (COLOR_ACTIVEBORDER);
	clrInactiveBorder = ::GetSysColor (COLOR_INACTIVEBORDER);

	clrInactiveCaptionText = ::GetSysColor (COLOR_INACTIVECAPTIONTEXT);

	OSVERSIONINFO osvi;
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

	::GetVersionEx (&osvi);

	if (m_bIsBlackHighContrast)
	{
		clrHotText = clrWindowText;
		clrHotLinkText = clrWindowText;
	}
	else
	{
		if (osvi.dwMajorVersion >= 5)
		{
			clrHotText = ::GetSysColor (26 /*COLOR_HOTLIGHT*/);
			clrHotLinkText = RGB (0, 0, 255);	// Light blue
		}
		else
		{
			clrHotText = RGB (0, 0, 255);		// Light blue
			clrHotLinkText = RGB (255, 0, 255);	// Violet
		}
	}

	hbrBtnShadow = ::GetSysColorBrush (COLOR_BTNSHADOW);
	ASSERT(hbrBtnShadow != NULL);

	hbrBtnHilite = ::GetSysColorBrush (COLOR_BTNHIGHLIGHT);
	ASSERT(hbrBtnHilite != NULL);

	hbrWindow = ::GetSysColorBrush (COLOR_WINDOW);
	ASSERT(hbrWindow != NULL);

	brBtnFace.DeleteObject ();
	brBtnFace.CreateSolidBrush (clrBtnFace);

	brBarFace.DeleteObject ();
	brBarFace.CreateSolidBrush (clrBarFace);

	brActiveCaption.DeleteObject ();
	brActiveCaption.CreateSolidBrush (clrActiveCaption);

	brInactiveCaption.DeleteObject ();
	brInactiveCaption.CreateSolidBrush (clrInactiveCaption);

	brHilite.DeleteObject ();
	brHilite.CreateSolidBrush (clrHilite);

	brBlack.DeleteObject ();
	brBlack.CreateSolidBrush (clrBtnDkShadow);

	brWindow.DeleteObject ();
	brWindow.CreateSolidBrush (clrWindow);

	penHilite.DeleteObject ();
	penHilite.CreatePen (PS_SOLID, 1, globalData.clrHilite);

	penBarFace.DeleteObject ();
	penBarFace.CreatePen (PS_SOLID, 1, globalData.clrBarFace);

	penBarShadow.DeleteObject ();
	penBarShadow.CreatePen (PS_SOLID, 1, globalData.clrBarShadow);

	if (brLight.GetSafeHandle ())
	{
		brLight.DeleteObject ();
	}
	
	if (m_nBitsPerPixel > 8)
	{
		COLORREF clrLight = RGB (
			GetRValue(clrBtnFace) + ((GetRValue(clrBtnHilite) -
				GetRValue(clrBtnFace)) / 2 ),
			GetGValue(clrBtnFace) + ((GetGValue(clrBtnHilite) -
				GetGValue(clrBtnFace)) / 2),
			GetBValue(clrBtnFace) + ((GetBValue(clrBtnHilite) -
				GetBValue(clrBtnFace)) / 2)
			);

		brLight.CreateSolidBrush (clrLight);
	}
	else
	{
		HBITMAP hbmGray = CreateDitherBitmap (dc.GetSafeHdc ());
		ASSERT (hbmGray != NULL);

		CBitmap bmp;
		bmp.Attach (hbmGray);

		brLight.CreatePatternBrush (&bmp);
	}
}
//************************************************************************************
BOOL MYGLOBAL_DATA::SetMenuFont (LPLOGFONT lpLogFont, BOOL bHorz)
{
	ASSERT (lpLogFont != NULL);

	if (bHorz)
	{
		//---------------------
		// Create regular font:
		//---------------------
		fontRegular.DeleteObject ();
		if (!fontRegular.CreateFontIndirect (lpLogFont))
		{
			ASSERT (FALSE);
			return FALSE;
		}

		//-----------------------
		// Create underline font:
		//-----------------------
		lpLogFont->lfUnderline = TRUE;
		fontUnderline.DeleteObject ();
		fontUnderline.CreateFontIndirect (lpLogFont);
		lpLogFont->lfUnderline = FALSE;

		//---------------------------------------------------
		// Create bold font (used in the default menu items):
		//---------------------------------------------------
		long lSavedWeight = lpLogFont->lfWeight;
		lpLogFont->lfWeight = 700;

		fontBold.DeleteObject ();
		BOOL bResult = fontBold.CreateFontIndirect (lpLogFont);

		lpLogFont->lfWeight = lSavedWeight;	// Restore weight

		if (!bResult)
		{
			ASSERT (FALSE);
			return FALSE;
		}
	}
	else	// Vertical font
	{
		fontVert.DeleteObject ();
		if (!fontVert.CreateFontIndirect (lpLogFont))
		{
			ASSERT (FALSE);
			return FALSE;
		}
	}

	UpdateTextMetrics();
	return TRUE;
}
//************************************************************************************
void MYGLOBAL_DATA::UpdateTextMetrics ()
{
	CWindowDC dc (NULL);

	CFont* pOldFont = dc.SelectObject (&fontRegular);
	ASSERT (pOldFont != NULL);

	TEXTMETRIC tm;
	dc.GetTextMetrics (&tm);

	m_nTextMarginsHorz = tm.tmHeight < 15 ? 2 : 5;
	m_nTextHeightHorz = tm.tmHeight + m_nTextMarginsHorz;
	m_nTextWidthHorz = tm.tmMaxCharWidth + m_nTextMarginsHorz;

	dc.SelectObject (&fontVert);
	dc.GetTextMetrics (&tm);

	m_nTextMarginsVert = tm.tmHeight < 15 ? 2 : 5;

	m_nTextHeightVert = tm.tmHeight + m_nTextMarginsVert;
	m_nTextWidthVert = tm.tmMaxCharWidth + m_nTextMarginsVert;

	dc.SelectObject (pOldFont);
}
//*******************************************************************************
HBITMAP MYGLOBAL_DATA::CreateDitherBitmap (HDC hDC)
{
	struct  // BITMAPINFO with 16 colors
	{
		BITMAPINFOHEADER bmiHeader;
		RGBQUAD      bmiColors[16];
	} 
	bmi;
	memset(&bmi, 0, sizeof(bmi));

	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = 8;
	bmi.bmiHeader.biHeight = 8;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 1;
	bmi.bmiHeader.biCompression = BI_RGB;

	COLORREF clr = globalData.clrBtnFace;

	bmi.bmiColors[0].rgbBlue = GetBValue(clr);
	bmi.bmiColors[0].rgbGreen = GetGValue(clr);
	bmi.bmiColors[0].rgbRed = GetRValue(clr);

	clr = ::GetSysColor(COLOR_BTNHIGHLIGHT);
	bmi.bmiColors[1].rgbBlue = GetBValue(clr);
	bmi.bmiColors[1].rgbGreen = GetGValue(clr);
	bmi.bmiColors[1].rgbRed = GetRValue(clr);

	// initialize the brushes
	long patGray[8];
	for (int i = 0; i < 8; i++)
	   patGray[i] = (i & 1) ? 0xAAAA5555L : 0x5555AAAAL;

	HBITMAP hbm = CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT,
		(LPBYTE)patGray, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
	return hbm;
}
//*************************************************************************************
void MYGLOBAL_DATA::CleanUp ()
{
	if (brLight.GetSafeHandle ())
	{
		brLight.DeleteObject ();
	}
	
	// cleanup fonts:
	fontRegular.DeleteObject ();
	fontBold.DeleteObject ();
	fontUnderline.DeleteObject ();
	fontVert.DeleteObject ();
	fontVertCaption.DeleteObject ();
	fontTooltip.DeleteObject ();

	if (m_hinstUXThemeDLL != NULL)
	{
		::FreeLibrary (m_hinstUXThemeDLL);
		m_hinstUXThemeDLL = NULL;
	}

	if (m_hinstUser32 != NULL)
	{
		::FreeLibrary (m_hinstUser32);
		m_hinstUser32 = NULL;
	}

	if (m_hinstDwmapiDLL != NULL)
	{
		::FreeLibrary (m_hinstDwmapiDLL);
		m_hinstDwmapiDLL = NULL;
	}
}
//*************************************************************************************
void MyCBProCleanUp ()
{
	globalData.CleanUp ();
}
//****************************************************************************************
BOOL MYGLOBAL_DATA::DrawParentBackground (CWnd* pWnd, CDC* pDC, LPRECT rectClip)
{
	ASSERT_VALID (pDC);
	ASSERT_VALID (pWnd);

	BOOL bRes = FALSE;

	CRgn rgn;
	if (rectClip != NULL)
	{
		rgn.CreateRectRgnIndirect (rectClip);
		pDC->SelectClipRgn (&rgn);
	}

	CWnd* pParent = pWnd->GetParent ();
	ASSERT_VALID (pParent);

	// In Windows XP, we need to call DrawThemeParentBackground function to implement
	// transparent controls
	if (m_pfDrawThemeBackground != NULL)
	{
		bRes = (*m_pfDrawThemeBackground) (pWnd->GetSafeHwnd (), 
			pDC->GetSafeHdc (), rectClip) == S_OK;
	}

	if (!bRes)
	{
		CPoint pt (0, 0);
		pWnd->MapWindowPoints (pParent, &pt, 1);
		pt = pDC->OffsetWindowOrg (pt.x, pt.y);

		bRes = (BOOL) pParent->SendMessage (WM_ERASEBKGND, (WPARAM)pDC->m_hDC);

		pDC->SetWindowOrg(pt.x, pt.y);
	}

	pDC->SelectClipRgn (NULL);

	return bRes;
}

COLORREF MYGLOBAL_DATA::GetColor (int nColor)
{
	switch (nColor)
	{
	case COLOR_BTNFACE:             return clrBtnFace;
	case COLOR_BTNSHADOW:           return clrBtnShadow;			
	case COLOR_3DDKSHADOW:          return clrBtnDkShadow;			
	case COLOR_3DLIGHT:             return clrBtnLight;				
	case COLOR_BTNHIGHLIGHT:        return clrBtnHilite;			
	case COLOR_BTNTEXT:             return clrBtnText;				
	case COLOR_GRAYTEXT:            return clrGrayedText;			
	case COLOR_WINDOWFRAME:         return clrWindowFrame;			
	                          
	case COLOR_HIGHLIGHT:           return clrHilite;				
	case COLOR_HIGHLIGHTTEXT:       return clrTextHilite;			
	                          
	case COLOR_WINDOW:				return clrWindow;				
	case COLOR_WINDOWTEXT:			return clrWindowText;			
	                          
	case COLOR_CAPTIONTEXT:			return clrCaptionText;			
	case COLOR_MENUTEXT:			return clrMenuText;				
	                          
	case COLOR_ACTIVECAPTION:		return clrActiveCaption;		
	case COLOR_INACTIVECAPTION:		return clrInactiveCaption;		
	                          
	case COLOR_ACTIVEBORDER:		return clrActiveBorder;			
	case COLOR_INACTIVEBORDER:		return clrInactiveBorder;
	                          
	case COLOR_INACTIVECAPTIONTEXT:	return clrInactiveCaptionText;
	}

	return ::GetSysColor (nColor);
}
//******************************************************************************
BOOL MYGLOBAL_DATA::SetLayeredAttrib (HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags)
{
	if (m_pfSetLayeredWindowAttributes == NULL)
	{
		return FALSE;
	}

	return (*m_pfSetLayeredWindowAttributes) (hwnd, crKey, bAlpha, dwFlags);
}

BOOL MYGLOBAL_DATA::UpdateLayeredWindow (HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc,
							POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags)
{
	if (m_pfUpdateLayeredWindow == NULL)
	{
		return FALSE;
	}

	return (*m_pfUpdateLayeredWindow) (hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
}

CString MYGLOBAL_DATA::RegisterWindowClass (LPCTSTR lpszClassNamePrefix)
{
	ASSERT (lpszClassNamePrefix != NULL);

	//-----------------------------
	// Register a new window class:
	//-----------------------------
	HINSTANCE hInst = AfxGetInstanceHandle();
	UINT uiClassStyle = CS_DBLCLKS;
	HCURSOR hCursor = ::LoadCursor (NULL, IDC_ARROW);
	HBRUSH hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

	CString strClassName;
	strClassName.Format (_T("%s:%x:%x:%x:%x"), 
		lpszClassNamePrefix,
		(UINT_PTR)hInst, uiClassStyle, (UINT_PTR)hCursor, (UINT_PTR)hbrBackground);

	//---------------------------------
	// See if the class already exists:
	//---------------------------------
	WNDCLASS wndcls;
	if (::GetClassInfo (hInst, strClassName, &wndcls))
	{
		//-----------------------------------------------
		// Already registered, assert everything is good:
		//-----------------------------------------------
		ASSERT (wndcls.style == uiClassStyle);
	}
	else
	{
		//-------------------------------------------
		// Otherwise we need to register a new class:
		//-------------------------------------------
		wndcls.style = uiClassStyle;
		wndcls.lpfnWndProc = ::DefWindowProc;
		wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
		wndcls.hInstance = hInst;
		wndcls.hIcon = NULL;
		wndcls.hCursor = hCursor;
		wndcls.hbrBackground = hbrBackground;
		wndcls.lpszMenuName = NULL;
		wndcls.lpszClassName = strClassName;
		
		if (!AfxRegisterClass (&wndcls))
		{
			AfxThrowResourceException();
		}
	}

	return strClassName;
}
//*************************************************************************************
BOOL MYGLOBAL_DATA::ExcludeTag (CString& strBuffer, 
						LPCTSTR lpszTag,
						CString& strTag, BOOL bIsCharsList /* = FALSE*/)
{
	const int iBufLen = strBuffer.GetLength ();

	CString strTagStart = _T("<");
	strTagStart += lpszTag;
	strTagStart += _T('>');

	const int iTagStartLen = strTagStart.GetLength ();

	int iStart = -1;

	int iIndexStart = strBuffer.Find (strTagStart);
	if (iIndexStart < 0)
	{
		return FALSE;
	}

	iStart = iIndexStart + iTagStartLen;

	CString strTagEnd = _T("</");
	strTagEnd += lpszTag;
	strTagEnd += _T('>');

	const int iTagEndLen = strTagEnd.GetLength ();

	int iIndexEnd =  -1;
	int nBalanse = 1;
	for (int i = iStart; i < iBufLen - iTagEndLen + 1; i ++)
	{
		if (strBuffer [i] != '<')
		{
			continue;
		}

		if (i < iBufLen - iTagStartLen &&
			_tcsncmp (strBuffer.Mid (i), strTagStart, iTagStartLen) == 0)
		{
			i += iTagStartLen - 1;
			nBalanse ++;
			continue;
		}

		if (_tcsncmp (strBuffer.Mid (i), strTagEnd, iTagEndLen) == 0)
		{
			nBalanse --;
			if (nBalanse == 0)
			{
				iIndexEnd = i;
				break;
			}

			i += iTagEndLen - 1;
		}
	}

	if (iIndexEnd == -1 || iStart > iIndexEnd)
	{
		return FALSE;
	}

	strTag = strBuffer.Mid (iStart, iIndexEnd - iStart);
	strTag.TrimLeft ();
	strTag.TrimRight ();

	strBuffer.Delete (iIndexStart, iIndexEnd + iTagEndLen - iIndexStart);

	if (bIsCharsList)
	{
		if (strTag.GetLength () > 1 && strTag [0] == _T('\"'))
		{
			strTag = strTag.Mid (1, strTag.GetLength () - 2);
		}

		strTag.Replace (_T("\\t"), _T("\t"));
		strTag.Replace (_T("\\n"), _T("\n"));
		strTag.Replace (_T("\\r"), _T("\r"));
		strTag.Replace (_T("\\b"), _T("\b"));
		strTag.Replace (_T("LT"), _T("<"));
		strTag.Replace (_T("GT"), _T(">"));
		strTag.Replace (_T("AMP"), _T("&"));
	}

	return TRUE;
}
//***********************************************************************************************
BOOL MYGLOBAL_DATA::DwmExtendFrameIntoClientArea (HWND hWnd, MYMARGINS* pMargins)
{
	if (m_pfDwmExtendFrameIntoClientArea == NULL)
	{
		return FALSE;
	}

	HRESULT hres = (*m_pfDwmExtendFrameIntoClientArea) (hWnd, pMargins);
	return hres == S_OK;
}
//***********************************************************************************************
LRESULT MYGLOBAL_DATA::DwmDefWindowProc (HWND hWnd, UINT message, WPARAM wp, LPARAM lp)
{
	if (m_pfDwmDefWindowProc == NULL)
	{
		return (LRESULT)-1;
	}

	LRESULT lres = 0;
	(*m_pfDwmDefWindowProc) (hWnd, message, wp, lp, &lres);

	return lres;
}
//***********************************************************************************************
BOOL MYGLOBAL_DATA::DwmIsCompositionEnabled ()
{
	if (m_pfDwmIsCompositionEnabled == NULL || bDisableAero)
	{
		return FALSE;
	}

	BOOL bEnabled = FALSE;

	(*m_pfDwmIsCompositionEnabled) (&bEnabled);
	return bEnabled;
}
//***********************************************************************************************
BOOL MYGLOBAL_DATA::DrawTextOnGlass (HTHEME hTheme, CDC* pDC, int iPartId, int iStateId, 
								   CString strText, CRect rect, DWORD dwFlags,
								   int nGlowSize, COLORREF clrText)
{

//---- bits used in dwFlags of DTTOPTS ----
#define MY_DTT_TEXTCOLOR       (1UL << 0)      // crText has been specified
#define MY_DTT_BORDERCOLOR     (1UL << 1)      // crBorder has been specified
#define MY_DTT_SHADOWCOLOR     (1UL << 2)      // crShadow has been specified
#define MY_DTT_SHADOWTYPE      (1UL << 3)      // iTextShadowType has been specified
#define MY_DTT_SHADOWOFFSET    (1UL << 4)      // ptShadowOffset has been specified
#define MY_DTT_BORDERSIZE      (1UL << 5)      // iBorderSize has been specified
#define MY_DTT_FONTPROP        (1UL << 6)      // iFontPropId has been specified
#define MY_DTT_COLORPROP       (1UL << 7)      // iColorPropId has been specified
#define MY_DTT_STATEID         (1UL << 8)      // IStateId has been specified
#define MY_DTT_CALCRECT        (1UL << 9)      // Use pRect as and in/out parameter
#define MY_DTT_APPLYOVERLAY    (1UL << 10)     // fApplyOverlay has been specified
#define MY_DTT_GLOWSIZE        (1UL << 11)     // iGlowSize has been specified
#define MY_DTT_CALLBACK        (1UL << 12)     // pfnDrawTextCallback has been specified
#define MY_DTT_COMPOSITED      (1UL << 13)     // Draws text with antialiased alpha (needs a DIB section)

	if (hTheme == NULL ||
		m_pfDrawThemeTextEx == NULL || !DwmIsCompositionEnabled ())
	{
		pDC->DrawText (strText, rect, dwFlags);
		return FALSE;
	}

	_bstr_t bstmp = (LPCTSTR) strText; 

	wchar_t* wbuf = new wchar_t[bstmp.length() + 1];
#if _MSC_VER < 1400
	wcscpy (wbuf, bstmp);
#else
    wcscpy_s (wbuf, bstmp.length() + 1, bstmp);
#endif

	MYDTTOPTS dto;
	memset (&dto, 0, sizeof (MYDTTOPTS));
	dto.dwSize = sizeof (MYDTTOPTS);
	dto.dwFlags = MY_DTT_COMPOSITED;

	if (nGlowSize > 0)
	{
		dto.dwFlags |= MY_DTT_GLOWSIZE;
		dto.iGlowSize = nGlowSize;
	}

	if (clrText != (COLORREF)-1)
	{
		dto.dwFlags |= MY_DTT_TEXTCOLOR;
		dto.crText = clrText;
	}

	(*m_pfDrawThemeTextEx) (hTheme, pDC->GetSafeHdc (), iPartId, iStateId, wbuf, -1, 
		dwFlags, rect, &dto);

	delete [] wbuf;

	return TRUE;
}
//******************************************************************************************************************
BOOL MYGLOBAL_DATA::DrawIconOnGlass (HTHEME hTheme, CDC* pDC, HICON hIcon, CRect rect)
{
	ASSERT_VALID (pDC);

	if (hTheme == NULL || m_pfDrawThemeIcon == NULL || !DwmIsCompositionEnabled ())
	{
		pDC->DrawState (rect.TopLeft (), rect.Size (), hIcon, DSS_NORMAL, (CBrush*)NULL);
		return FALSE;
	}

	CImageList images;
	images.Create (rect.Width (), rect.Height (), ILC_COLOR32 | ILC_MASK, 0, 0);
	images.Add (hIcon);

	(*m_pfDrawThemeIcon)(hTheme, pDC->GetSafeHdc (), 0, 0, rect, images.GetSafeHandle (), 0);

	return TRUE;
}
//***********************************************************************************************
HCURSOR	MYGLOBAL_DATA::GetHandCursor ()
{
	if (m_hcurHand == NULL)
	{
		m_hcurHand = ::LoadCursor (NULL, MAKEINTRESOURCE(32649)/*IDC_HAND*/);
	}

	return m_hcurHand;
}
//***********************************************************************************************

struct MY_DLLVERSIONINFO
{
		DWORD cbSize;
		DWORD dwMajorVersion;                   // Major version
		DWORD dwMinorVersion;                   // Minor version
		DWORD dwBuildNumber;                    // Build number
		DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
};

typedef HRESULT (CALLBACK* MY_DLLGETVERSIONPROC)(MY_DLLVERSIONINFO *);

DWORD MYGLOBAL_DATA::GetComCtlVersion ()
{
	if (m_dwComCtlVersion != -1)
	{
		return m_dwComCtlVersion;
	}

	HINSTANCE hInst = ::GetModuleHandle(_T("COMCTL32"));
	ASSERT(hInst != NULL);

	MY_DLLGETVERSIONPROC pfn;

	pfn = (MY_DLLGETVERSIONPROC)GetProcAddress(hInst, "DllGetVersion");
	DWORD dwVersion =  MAKELONG(0, 4);

	if (pfn != NULL)
	{
		MY_DLLVERSIONINFO dvi;
		memset(&dvi, 0, sizeof(dvi));
		dvi.cbSize = sizeof(dvi);
		HRESULT hr = (*pfn)(&dvi);
		if (SUCCEEDED(hr))
		{
			ASSERT(dvi.dwMajorVersion <= 0xFFFF);
			ASSERT(dvi.dwMinorVersion <= 0xFFFF);
			dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
		}
	}

	m_dwComCtlVersion = dwVersion;
	return m_dwComCtlVersion;
}

BOOL MYGLOBAL_DATA::GetNonClientMetrics (NONCLIENTMETRICS& ncm)
{
	struct MY_OLDNONCLIENTMETRICS
	{
		UINT    cbSize;
		int     iBorderWidth;
		int     iScrollWidth;
		int     iScrollHeight;
		int     iCaptionWidth;
		int     iCaptionHeight;
		LOGFONT lfCaptionFont;
		int     iSmCaptionWidth;
		int     iSmCaptionHeight;
		LOGFONT lfSmCaptionFont;
		int     iMenuWidth;
		int     iMenuHeight;
		LOGFONT lfMenuFont;
		LOGFONT lfStatusFont;
		LOGFONT lfMessageFont;
	};

	const UINT cbProperSize = (GetComCtlVersion () < MAKELONG(1, 6))
		? sizeof(MY_OLDNONCLIENTMETRICS) : sizeof(NONCLIENTMETRICS);

	ZeroMemory (&ncm, sizeof (NONCLIENTMETRICS));
	ncm.cbSize = cbProperSize;

	return ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, cbProperSize, &ncm, 0);
}

UINT MYGLOBAL_DATA::GetRebarBandInfoSize ()
{
	struct MY_OLDREBARBANDINFO
	{
		UINT cbSize;
		UINT fMask;
		UINT fStyle;
		COLORREF clrFore;
		COLORREF clrBack;
		LPTSTR lpText;
		UINT cch;
		int iImage;
		HWND hwndChild;
		UINT cxMinChild;
		UINT cyMinChild;
		UINT cx;
		HBITMAP hbmBack;
		UINT wID;
	#if (_WIN32_IE >= 0x0400)
		UINT cyChild;  
		UINT cyMaxChild;
		UINT cyIntegral;
		UINT cxIdeal;
		LPARAM lParam;
		UINT cxHeader;
	#endif
	};

	return (GetComCtlVersion () < MAKELONG(1, 6))
		? sizeof(MY_OLDREBARBANDINFO) : sizeof(REBARBANDINFO);
}

BOOL MYGLOBAL_DATA::SetDPIAware ()
{
	if (m_hinstUser32 == NULL)
	{
		ASSERT (FALSE);
		return FALSE;
	}

typedef BOOL (__stdcall * MYSETPROCESSDPIAWARE)();
	
	MYSETPROCESSDPIAWARE pSetDPIAware =
		(MYSETPROCESSDPIAWARE)::GetProcAddress(m_hinstUser32, "SetProcessDPIAware");

	if (pSetDPIAware == NULL)
	{
		return FALSE;
	}

	BOOL bRes = (*pSetDPIAware) ();

	UpdateSysColors();
	UpdateFonts();
	OnSettingChange ();

   return bRes;
}
